/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright (C) 1993-2017 Free Software Foundation, Inc.
+ Copyright (C) 1993-2019 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
extension. */
unsigned long insn_opcode;
+ /* The name if this is an label. */
+ char label[16];
+
+ /* The target label name if this is an branch. */
+ char target[16];
+
/* The frag that contains the instruction. */
struct frag *frag;
/* 1 if single-precision operations on odd-numbered registers are
allowed. */
int oddspreg;
+
+ /* The set of ASEs that should be enabled for the user specified
+ architecture. This cannot be inferred from 'arch' for all cores
+ as processors only have a unique 'arch' if they add architecture
+ specific instructions (UDI). */
+ int init_ase;
};
/* Specifies whether module level options have been checked yet. */
/* 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, /* oddspreg */ -1
+ /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1,
+ /* init_ase */ 0
};
/* This is similar to file_mips_opts, but for the current set of options. */
/* 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, /* oddspreg */ -1
+ /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1,
+ /* init_ase */ 0
};
/* Which bits of file_ase were explicitly set or cleared by ASE options. */
|| (ISA) == ISA_MIPS64R5 \
|| (ISA) == ISA_MIPS64R6 \
|| (CPU) == CPU_R5900) \
- && (CPU) != CPU_LOONGSON_3A)
+ && ((CPU) != CPU_GS464 \
+ || (CPU) != CPU_GS464E \
+ || (CPU) != CPU_GS264E))
/* Return true if ISA supports move to/from high part of a 64-bit
floating-point register. */
/* True if CPU has a ror instruction. */
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
-/* True if CPU is in the Octeon family */
+/* True if CPU is in the Octeon family. */
#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
|| (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
fixed it for the non-PIC mode. KR 95/04/07 */
static int nopic_need_relax (symbolS *, int);
-/* handle of the OPCODE hash table */
+/* Handle of the OPCODE hash table. */
static struct hash_control *op_hash = NULL;
/* The opcode hash table we use for the mips16. */
static struct hash_control *micromips_op_hash = NULL;
/* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
+ pre-processor is disabled, these aren't very useful. */
const char comment_chars[] = "#";
/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output */
+ .line and .file directives will appear in the pre-processed output. */
/* Note that input_file.c hand checks for '#' at the beginning of the
first line of the input file. This is because the compiler outputs
#NO_APP at the beginning of its output. */
/* This array holds machine specific line separator characters. */
const char line_separator_chars[] = ";";
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant from exp in floating point nums. */
const char EXP_CHARS[] = "eE";
-/* Chars that mean this number is a floating point constant */
-/* As in 0f12.456 */
-/* or 0d1.2345e12 */
+/* Chars that mean this number is a floating point constant.
+ As in 0f12.456
+ or 0d1.2345e12. */
const char FLT_CHARS[] = "rRsSfFdDxXpP";
/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
changed in read.c . Ideally it shouldn't have to know about it at all,
- but nothing is ideal around here.
- */
+ but nothing is ideal around here. */
/* Types of printf format used for instruction-related error messages.
- "I" means int ("%d") and "S" means string ("%s"). */
-enum mips_insn_error_format {
+ "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 {
+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
/* The printf()-style message, including its format and arguments. */
enum mips_insn_error_format format;
const char *msg;
- union {
+ union
+ {
int i;
const char *ss[2];
} u;
/* The maximum number of NOPs needed for any purpose. */
#define MAX_NOPS 4
+/* The maximum range of context length of ll/sc. */
+#define MAX_LLSC_RANGE 20
+
/* A list of previous instructions, with index 0 being the most recent.
We need to look back MAX_NOPS instructions when filling delay slots
or working around processor errata. We need to look back one
instruction further if we're thinking about using history[0] to
fill a branch delay slot. */
-static struct mips_cl_insn history[1 + MAX_NOPS];
+static struct mips_cl_insn history[1 + MAX_NOPS + MAX_LLSC_RANGE];
/* Arrays of operands for each instruction. */
#define MAX_OPERANDS 6
-struct mips_operand_array {
+struct mips_operand_array
+{
const struct mips_operand *operand[MAX_OPERANDS];
};
static struct mips_operand_array *mips_operands;
static struct mips_cl_insn micromips_nop16_insn;
static struct mips_cl_insn micromips_nop32_insn;
+/* Sync instructions used by insert sync. */
+static struct mips_cl_insn sync_insn;
+
/* The appropriate nop for the current mode. */
#define NOP_INSN (mips_opts.mips16 \
? &mips16_nop_insn \
/* ...likewise -mfix-cn63xxp1 */
static bfd_boolean mips_fix_cn63xxp1;
+/* ...likewise -mfix-r5900 */
+static bfd_boolean mips_fix_r5900;
+static bfd_boolean mips_fix_r5900_explicit;
+
+/* ...likewise -mfix-loongson3-llsc. */
+static bfd_boolean mips_fix_loongson3_llsc = DEFAULT_MIPS_FIX_LOONGSON3_LLSC;
+
/* We don't relax branches by default, since this causes us to expand
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we
fail to compute the offset before expanding the macro to the most
store whether this is known to be a branch to a different section,
whether we have tried to relax this frag yet, and whether we have
ever extended a PC relative fragment because of a shift count. */
-#define RELAX_MIPS16_ENCODE(type, pic, sym32, nomacro, \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro, \
small, ext, \
dslot, jal_dslot) \
(0x80000000 \
| ((type) & 0xff) \
- | ((pic) ? 0x100 : 0) \
- | ((sym32) ? 0x200 : 0) \
- | ((nomacro) ? 0x400 : 0) \
- | ((small) ? 0x800 : 0) \
- | ((ext) ? 0x1000 : 0) \
- | ((dslot) ? 0x2000 : 0) \
- | ((jal_dslot) ? 0x4000 : 0))
+ | ((e2) ? 0x100 : 0) \
+ | ((pic) ? 0x200 : 0) \
+ | ((sym32) ? 0x400 : 0) \
+ | ((nomacro) ? 0x800 : 0) \
+ | ((small) ? 0x1000 : 0) \
+ | ((ext) ? 0x2000 : 0) \
+ | ((dslot) ? 0x4000 : 0) \
+ | ((jal_dslot) ? 0x8000 : 0))
#define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
-#define RELAX_MIPS16_PIC(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_SYM32(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x4000) != 0)
-
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x8000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x8000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x8000)
-#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x10000) != 0)
-#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x10000)
-#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x10000)
-#define RELAX_MIPS16_MACRO(i) (((i) & 0x20000) != 0)
-#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x20000)
-#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_E2(i) (((i) & 0x100) != 0)
+#define RELAX_MIPS16_PIC(i) (((i) & 0x200) != 0)
+#define RELAX_MIPS16_SYM32(i) (((i) & 0x400) != 0)
+#define RELAX_MIPS16_NOMACRO(i) (((i) & 0x800) != 0)
+#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x1000) != 0)
+#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x2000) != 0)
+#define RELAX_MIPS16_DSLOT(i) (((i) & 0x4000) != 0)
+#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x8000) != 0)
+
+#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x10000) != 0)
+#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x10000)
+#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) & ~0x10000)
+#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x20000) != 0)
+#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x20000)
+#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x20000)
+#define RELAX_MIPS16_MACRO(i) (((i) & 0x40000) != 0)
+#define RELAX_MIPS16_MARK_MACRO(i) ((i) | 0x40000)
+#define RELAX_MIPS16_CLEAR_MACRO(i) ((i) & ~0x40000)
/* For microMIPS code, we use relaxation similar to one we use for
MIPS16 code. Some instructions that take immediate values support
static void mips16_macro (struct mips_cl_insn * ip);
static void mips_ip (char *str, struct mips_cl_insn * ip);
static void mips16_ip (char *str, struct mips_cl_insn * ip);
+static unsigned long mips16_immed_extend (offsetT, unsigned int);
static void mips16_immed
(const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
unsigned int, unsigned long *);
OPTION_NO_MICROMIPS,
OPTION_MCU,
OPTION_NO_MCU,
- OPTION_COMPAT_ARCH_BASE,
+ OPTION_MIPS16E2,
+ OPTION_NO_MIPS16E2,
+ OPTION_CRC,
+ OPTION_NO_CRC,
OPTION_M4650,
OPTION_NO_M4650,
OPTION_M4010,
OPTION_NO_FIX_24K,
OPTION_FIX_RM7000,
OPTION_NO_FIX_RM7000,
+ OPTION_FIX_LOONGSON3_LLSC,
+ OPTION_NO_FIX_LOONGSON3_LLSC,
OPTION_FIX_LOONGSON2F_JUMP,
OPTION_NO_FIX_LOONGSON2F_JUMP,
OPTION_FIX_LOONGSON2F_NOP,
OPTION_NO_FIX_VR4130,
OPTION_FIX_CN63XXP1,
OPTION_NO_FIX_CN63XXP1,
+ OPTION_FIX_R5900,
+ OPTION_NO_FIX_R5900,
OPTION_TRAP,
OPTION_BREAK,
OPTION_EB,
OPTION_NAN,
OPTION_ODD_SPREG,
OPTION_NO_ODD_SPREG,
+ OPTION_GINV,
+ OPTION_NO_GINV,
+ OPTION_LOONGSON_MMI,
+ OPTION_NO_LOONGSON_MMI,
+ OPTION_LOONGSON_CAM,
+ OPTION_NO_LOONGSON_CAM,
+ OPTION_LOONGSON_EXT,
+ OPTION_NO_LOONGSON_EXT,
+ OPTION_LOONGSON_EXT2,
+ OPTION_NO_LOONGSON_EXT2,
OPTION_END_OF_ENUM
};
{"mno-msa", no_argument, NULL, OPTION_NO_MSA},
{"mxpa", no_argument, NULL, OPTION_XPA},
{"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
+ {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2},
+ {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2},
+ {"mcrc", no_argument, NULL, OPTION_CRC},
+ {"mno-crc", no_argument, NULL, OPTION_NO_CRC},
+ {"mginv", no_argument, NULL, OPTION_GINV},
+ {"mno-ginv", no_argument, NULL, OPTION_NO_GINV},
+ {"mloongson-mmi", no_argument, NULL, OPTION_LOONGSON_MMI},
+ {"mno-loongson-mmi", no_argument, NULL, OPTION_NO_LOONGSON_MMI},
+ {"mloongson-cam", no_argument, NULL, OPTION_LOONGSON_CAM},
+ {"mno-loongson-cam", no_argument, NULL, OPTION_NO_LOONGSON_CAM},
+ {"mloongson-ext", no_argument, NULL, OPTION_LOONGSON_EXT},
+ {"mno-loongson-ext", no_argument, NULL, OPTION_NO_LOONGSON_EXT},
+ {"mloongson-ext2", no_argument, NULL, OPTION_LOONGSON_EXT2},
+ {"mno-loongson-ext2", no_argument, NULL, OPTION_NO_LOONGSON_EXT2},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
{"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
{"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
{"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+ {"mfix-loongson3-llsc", no_argument, NULL, OPTION_FIX_LOONGSON3_LLSC},
+ {"mno-fix-loongson3-llsc", no_argument, NULL, OPTION_NO_FIX_LOONGSON3_LLSC},
{"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
{"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
{"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
{"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},
+ {"mfix-r5900", no_argument, NULL, OPTION_FIX_R5900},
+ {"mno-fix-r5900", no_argument, NULL, OPTION_NO_FIX_R5900},
/* Miscellaneous options. */
{"trap", no_argument, NULL, OPTION_TRAP},
{ "xpa", ASE_XPA, 0,
OPTION_XPA, OPTION_NO_XPA,
- 2, 2, -1, -1,
+ 2, 2, 2, 2,
+ -1 },
+
+ { "mips16e2", ASE_MIPS16E2, 0,
+ OPTION_MIPS16E2, OPTION_NO_MIPS16E2,
+ 2, 2, -1, -1,
+ 6 },
+
+ { "crc", ASE_CRC, ASE_CRC64,
+ OPTION_CRC, OPTION_NO_CRC,
+ 6, 6, -1, -1,
+ -1 },
+
+ { "ginv", ASE_GINV, 0,
+ OPTION_GINV, OPTION_NO_GINV,
+ 6, 6, 6, 6,
+ -1 },
+
+ { "loongson-mmi", ASE_LOONGSON_MMI, 0,
+ OPTION_LOONGSON_MMI, OPTION_NO_LOONGSON_MMI,
+ 0, 0, -1, -1,
+ -1 },
+
+ { "loongson-cam", ASE_LOONGSON_CAM, 0,
+ OPTION_LOONGSON_CAM, OPTION_NO_LOONGSON_CAM,
+ 0, 0, -1, -1,
+ -1 },
+
+ { "loongson-ext", ASE_LOONGSON_EXT, 0,
+ OPTION_LOONGSON_EXT, OPTION_NO_LOONGSON_EXT,
+ 0, 0, -1, -1,
+ -1 },
+
+ { "loongson-ext2", ASE_LOONGSON_EXT | ASE_LOONGSON_EXT2, 0,
+ OPTION_LOONGSON_EXT2, OPTION_NO_LOONGSON_EXT2,
+ 0, 0, -1, -1,
-1 },
};
/* Groups of ASE_* flags that represent different revisions of an ASE. */
static const unsigned int mips_ase_groups[] = {
- ASE_DSP | ASE_DSPR2 | ASE_DSPR3
+ ASE_DSP | ASE_DSPR2 | ASE_DSPR3,
+ ASE_LOONGSON_EXT | ASE_LOONGSON_EXT2
};
\f
/* Pseudo-op table.
mask = mips_ase_mask (ase->flags);
opts->ase &= ~mask;
+
+ /* Clear combination ASE flags, which need to be recalculated based on
+ updated regular ASE settings. */
+ opts->ase &= ~(ASE_MIPS16E2_MT | ASE_XPA_VIRT | ASE_EVA_R6);
+
if (enabled_p)
opts->ase |= ase->flags;
+
+ /* The Virtualization ASE has eXtended Physical Addressing (XPA)
+ instructions which are only valid when both ASEs are enabled.
+ This sets the ASE_XPA_VIRT flag when both ASEs are present. */
+ if ((opts->ase & (ASE_XPA | ASE_VIRT)) == (ASE_XPA | ASE_VIRT))
+ {
+ opts->ase |= ASE_XPA_VIRT;
+ mask |= ASE_XPA_VIRT;
+ }
+ if ((opts->ase & (ASE_MIPS16E2 | ASE_MT)) == (ASE_MIPS16E2 | ASE_MT))
+ {
+ opts->ase |= ASE_MIPS16E2_MT;
+ mask |= ASE_MIPS16E2_MT;
+ }
+
+ /* The EVA Extension has instructions which are only valid when the R6 ISA
+ is enabled. This sets the ASE_EVA_R6 flag when both EVA and R6 ISA are
+ present. */
+ if (((opts->ase & ASE_EVA) != 0) && ISA_IS_R6 (opts->isa))
+ {
+ opts->ase |= ASE_EVA_R6;
+ mask |= ASE_EVA_R6;
+ }
+
return mask;
}
insn_insert_operand (struct mips_cl_insn *insn,
const struct mips_operand *operand, unsigned int uval)
{
- insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
+ if (mips_opts.mips16
+ && operand->type == OP_INT && operand->lsb == 0
+ && mips_opcode_32bit_p (insn->insn_mo))
+ insn->insn_opcode |= mips16_immed_extend (uval, operand->size);
+ else
+ insn->insn_opcode = mips_insert_operand (operand, insn->insn_opcode, uval);
}
/* Extract the value of OPERAND from INSN. */
{"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \
{"$ta3", RTYPE_GP | 15} /* alias for $t7 */
-/* Remaining symbolic register names */
+/* Remaining symbolic register names. */
#define SYMBOLIC_REGISTER_NAMES \
{"$zero", RTYPE_GP | 0}, \
{"$at", RTYPE_GP | 1}, \
{"$pc", RTYPE_PC | 0}
#define MDMX_VECTOR_REGISTER_NAMES \
- /* {"$v0", RTYPE_VEC | 0}, clash with REG 2 above */ \
- /* {"$v1", RTYPE_VEC | 1}, clash with REG 3 above */ \
+ /* {"$v0", RTYPE_VEC | 0}, Clash with REG 2 above. */ \
+ /* {"$v1", RTYPE_VEC | 1}, Clash with REG 3 above. */ \
{"$v2", RTYPE_VEC | 2}, \
{"$v3", RTYPE_VEC | 3}, \
{"$v4", RTYPE_VEC | 4}, \
static bfd_boolean
is_opcode_valid_16 (const struct mips_opcode *mo)
{
- return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch);
+ int isa = mips_opts.isa;
+ int ase = mips_opts.ase;
+ unsigned int i;
+
+ if (ISA_HAS_64BIT_REGS (isa))
+ for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+ if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+ ase |= mips_ases[i].flags64;
+
+ return opcode_is_member (mo, isa, ase, mips_opts.arch);
}
/* Return TRUE if the size of the microMIPS opcode MO matches one
}
gas_assert (opno < MAX_OPERANDS);
operands->operand[opno] = operand;
- if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
+ if (!decode_operand && operand
+ && operand->type == OP_INT && operand->lsb == 0
+ && mips_opcode_32bit_p (opcode))
+ used_bits |= mips16_immed_extend (-1, operand->size);
+ else if (operand && operand->type != OP_VU0_MATCH_SUFFIX)
{
used_bits = mips_insert_operand (operand, used_bits, -1);
if (operand->type == OP_MDMX_IMM_REG)
used_bits &= ~(1 << (operand->lsb + 5));
if (operand->type == OP_ENTRY_EXIT_LIST)
used_bits &= ~(mask & 0x700);
+ /* interAptiv MR2 SAVE/RESTORE instructions have a discontiguous
+ operand field that cannot be fully described with LSB/SIZE. */
+ if (operand->type == OP_SAVE_RESTORE_LIST && operand->lsb == 6)
+ used_bits &= ~0x6000;
}
/* Skip prefix characters. */
if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
decode_mips_operand, &mips_operands[i]))
broken = 1;
+
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&nop_insn, mips_opcodes + i);
nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
+
+ if (sync_insn.insn_mo == NULL && strcmp (name, "sync") == 0)
+ create_insn (&sync_insn, mips_opcodes + i);
+
++i;
}
while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
if (strncmp (TARGET_OS, "elf", 3) != 0
&& strncmp (TARGET_OS, "vxworks", 7) != 0)
{
- (void) bfd_set_section_alignment (stdoutput, text_section, 4);
- (void) bfd_set_section_alignment (stdoutput, data_section, 4);
- (void) bfd_set_section_alignment (stdoutput, bss_section, 4);
+ bfd_set_section_alignment (text_section, 4);
+ bfd_set_section_alignment (data_section, 4);
+ bfd_set_section_alignment (bss_section, 4);
}
/* Create a .reginfo section for register masks and a .mdebug
/* The ABI says this section should be loaded so that the
running program can access it. However, we don't load it
- if we are configured for an embedded target */
+ if we are configured for an embedded target. */
flags = SEC_READONLY | SEC_DATA;
if (strncmp (TARGET_OS, "elf", 3) != 0)
flags |= SEC_ALLOC | SEC_LOAD;
{
sec = subseg_new (".reginfo", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec, flags);
- bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
+ bfd_set_section_flags (sec, flags);
+ bfd_set_section_alignment (sec, HAVE_NEWABI ? 3 : 2);
mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
}
/* The 64-bit ABI uses a .MIPS.options section rather than
.reginfo section. */
sec = subseg_new (".MIPS.options", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec, flags);
- bfd_set_section_alignment (stdoutput, sec, 3);
+ bfd_set_section_flags (sec, flags);
+ bfd_set_section_alignment (sec, 3);
/* Set up the option header. */
{
}
sec = subseg_new (".MIPS.abiflags", (subsegT) 0);
- bfd_set_section_flags (stdoutput, sec,
+ bfd_set_section_flags (sec,
SEC_READONLY | SEC_DATA | SEC_ALLOC | SEC_LOAD);
- bfd_set_section_alignment (stdoutput, sec, 3);
+ bfd_set_section_alignment (sec, 3);
mips_flags_frag = frag_more (sizeof (Elf_External_ABIFlags_v0));
if (ECOFF_DEBUGGING)
{
sec = subseg_new (".mdebug", (subsegT) 0);
- (void) bfd_set_section_flags (stdoutput, sec,
- SEC_HAS_CONTENTS | SEC_READONLY);
- (void) bfd_set_section_alignment (stdoutput, sec, 2);
+ bfd_set_section_flags (sec, SEC_HAS_CONTENTS | SEC_READONLY);
+ bfd_set_section_alignment (sec, 2);
}
else if (mips_flag_pdr)
{
pdr_seg = subseg_new (".pdr", (subsegT) 0);
- (void) bfd_set_section_flags (stdoutput, pdr_seg,
- SEC_READONLY | SEC_RELOC
- | SEC_DEBUGGING);
- (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+ bfd_set_section_flags (pdr_seg,
+ SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
+ bfd_set_section_alignment (pdr_seg, 2);
}
subseg_set (seg, subseg);
static void
file_mips_check_options (void)
{
- const struct mips_cpu_info *arch_info = 0;
-
if (file_mips_opts_checked)
return;
file_mips_opts.fp = 32;
}
- arch_info = mips_cpu_info_from_arch (file_mips_opts.arch);
-
/* Disable operations on odd-numbered floating-point registers by default
when using the FPXX ABI. */
if (file_mips_opts.oddspreg < 0)
/* If the user didn't explicitly select or deselect a particular ASE,
use the default setting for the CPU. */
- file_mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
+ file_mips_opts.ase |= (file_mips_opts.init_ase & ~file_ase_explicit);
/* Set up the current options. These may change throughout assembly. */
mips_opts = file_mips_opts;
gas_assert (S_GET_SEGMENT (l->label) == now_seg);
symbol_set_frag (l->label, frag_now);
val = (valueT) frag_now_fix ();
- /* MIPS16/microMIPS text labels are stored as odd. */
+ /* MIPS16/microMIPS text labels are stored as odd.
+ We just carry the ISA mode bit forward. */
if (text_p && HAVE_CODE_COMPRESSION)
- ++val;
+ val |= (S_GET_VALUE (l->label) & 0x1);
S_SET_VALUE (l->label, val);
}
}
if (symseg != from_seg && !S_IS_LOCAL (sym))
{
- if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
+ if ((bfd_section_flags (symseg) & SEC_LINK_ONCE))
linkonce = TRUE;
/* The GNU toolchain uses an extension for ELF: a section
beginning with the magic string .gnu.linkonce is a
case OP_IMM_INDEX:
abort ();
+ case OP_REG28:
+ return 1 << 28;
+
case OP_REG:
case OP_OPTIONAL_REG:
{
}
/* Try to get a constant expression from the next tokens in ARG. Consume
- the tokens and return return true on success, storing the constant value
+ the tokens and return true on success, storing the constant value
in *VALUE. */
static bfd_boolean
{
max_val = ((1 << operand_base->size) - 1) << operand->shift;
if (!arg->lax_match && sval <= max_val)
- return FALSE;
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
}
}
else
return TRUE;
}
+/* Encode regular MIPS SAVE/RESTORE instruction operands according to
+ the argument register mask AMASK, the number of static registers
+ saved NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+ respectively, and the frame size FRAME_SIZE. */
+
+static unsigned int
+mips_encode_save_restore (unsigned int amask, unsigned int nsreg,
+ unsigned int ra, unsigned int s0, unsigned int s1,
+ unsigned int frame_size)
+{
+ return ((nsreg << 23) | ((frame_size & 0xf0) << 15) | (amask << 15)
+ | (ra << 12) | (s0 << 11) | (s1 << 10) | ((frame_size & 0xf) << 6));
+}
+
+/* Encode MIPS16 SAVE/RESTORE instruction operands according to the
+ argument register mask AMASK, the number of static registers saved
+ NSREG, the $ra, $s0 and $s1 register specifiers RA, S0 and S1
+ respectively, and the frame size FRAME_SIZE. */
+
+static unsigned int
+mips16_encode_save_restore (unsigned int amask, unsigned int nsreg,
+ unsigned int ra, unsigned int s0, unsigned int s1,
+ unsigned int frame_size)
+{
+ unsigned int args;
+
+ args = (ra << 6) | (s0 << 5) | (s1 << 4) | (frame_size & 0xf);
+ if (nsreg || amask || frame_size == 0 || frame_size > 16)
+ args |= (MIPS16_EXTEND | (nsreg << 24) | (amask << 16)
+ | ((frame_size & 0xf0) << 16));
+ return args;
+}
+
/* OP_SAVE_RESTORE_LIST matcher. */
static bfd_boolean
{
unsigned int opcode, args, statics, sregs;
unsigned int num_frame_sizes, num_args, num_statics, num_sregs;
+ unsigned int arg_mask, ra, s0, s1;
offsetT frame_size;
opcode = arg->insn->insn_opcode;
args = 0;
statics = 0;
sregs = 0;
+ ra = 0;
+ s0 = 0;
+ s1 = 0;
do
{
unsigned int regno1, regno2;
sregs |= 1 << 8;
else if (regno1 == 31)
/* Add $ra to insn. */
- opcode |= 0x40;
+ ra = 1;
else
return FALSE;
regno1 += 1;
return FALSE;
else if (args == 0xf)
/* All $a0-$a3 are args. */
- opcode |= MIPS16_ALL_ARGS << 16;
+ arg_mask = MIPS_SVRS_ALL_ARGS;
else if (statics == 0xf)
/* All $a0-$a3 are statics. */
- opcode |= MIPS16_ALL_STATICS << 16;
+ arg_mask = MIPS_SVRS_ALL_STATICS;
else
{
/* Count arg registers. */
return FALSE;
/* Encode args/statics. */
- opcode |= ((num_args << 2) | num_statics) << 16;
+ arg_mask = (num_args << 2) | num_statics;
}
/* Encode $s0/$s1. */
if (sregs & (1 << 0)) /* $s0 */
- opcode |= 0x20;
+ s0 = 1;
if (sregs & (1 << 1)) /* $s1 */
- opcode |= 0x10;
+ s1 = 1;
sregs >>= 2;
/* Encode $s2-$s8. */
}
if (sregs != 0)
return FALSE;
- opcode |= num_sregs << 24;
/* Encode frame size. */
if (num_frame_sizes == 0)
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));
- }
+ frame_size /= 8;
/* Finally build the instruction. */
- if ((opcode >> 16) != 0 || frame_size == 0)
- opcode |= MIPS16_EXTEND;
+ if (mips_opts.mips16)
+ opcode |= mips16_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+ frame_size);
+ else if (!mips_opts.micromips)
+ opcode |= mips_encode_save_restore (arg_mask, num_sregs, ra, s0, s1,
+ frame_size);
+ else
+ abort ();
+
arg->insn->insn_opcode = opcode;
return TRUE;
}
return FALSE;
}
+/* OP_REG28 matcher. */
+
+static bfd_boolean
+match_reg28_operand (struct mips_arg_info *arg)
+{
+ unsigned int regno;
+
+ if (arg->token->type == OT_REG
+ && match_regno (arg, OP_REG_GP, arg->token->u.regno, ®no)
+ && regno == GP)
+ {
+ ++arg->token;
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* OP_NON_ZERO_REG matcher. */
static bfd_boolean
return FALSE;
if (regno == 0)
- return FALSE;
+ {
+ set_insn_error (arg->argnum, _("the source register must not be $0"));
+ return FALSE;
+ }
arg->last_regno = regno;
insn_insert_operand (arg->insn, operand, regno);
return match_reg (arg, OP_REG_GP, ®no) && regno == other_regno;
}
-/* Read a floating-point constant from S for LI.S or LI.D. LENGTH is
- the length of the value in bytes (4 for float, 8 for double) and
- USING_GPRS says whether the destination is a GPR rather than an FPR.
+/* Try to match a floating-point constant from ARG for LI.S or LI.D.
+ LENGTH is the length of the value in bytes (4 for float, 8 for double)
+ and USING_GPRS says whether the destination is a GPR rather than an FPR.
Return the constant in IMM and OFFSET as follows:
}
new_seg = subseg_new (newname, (subsegT) 0);
- bfd_set_section_flags (stdoutput, new_seg,
+ bfd_set_section_flags (new_seg,
SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA);
frag_align (length == 4 ? 2 : 3, 0, 0);
if (strncmp (TARGET_OS, "elf", 3) != 0)
return TRUE;
}
-/* S is the text seen for ARG. Match it against OPERAND. Return the end
- of the argument text if the match is successful, otherwise return null. */
+/* Try to match a token from ARG against OPERAND. Consume the token
+ and return true on success, otherwise return false. */
static bfd_boolean
match_operand (struct mips_arg_info *arg,
case OP_PC:
return match_pc_operand (arg);
+ case OP_REG28:
+ return match_reg28_operand (arg);
+
case OP_VU0_SUFFIX:
return match_vu0_suffix_operand (arg, operand, FALSE);
fix_loongson2f_jump (ip);
}
+/* Fix loongson3 llsc errata: Insert sync before ll/lld. */
+
+static void
+fix_loongson3_llsc (struct mips_cl_insn * ip)
+{
+ gas_assert (!HAVE_CODE_COMPRESSION);
+
+ /* If is an local label and the insn is not sync,
+ look forward that whether an branch between ll/sc jump to here
+ if so, insert a sync. */
+ if (seg_info (now_seg)->label_list
+ && S_IS_LOCAL (seg_info (now_seg)->label_list->label)
+ && (strcmp (ip->insn_mo->name, "sync") != 0))
+ {
+ const char *label_name = S_GET_NAME (seg_info (now_seg)->label_list->label);
+ unsigned long lookback = ARRAY_SIZE (history);
+ unsigned long i;
+
+ for (i = 0; i < lookback; i++)
+ {
+ if (streq (history[i].insn_mo->name, "ll")
+ || streq (history[i].insn_mo->name, "lld"))
+ break;
+
+ if (streq (history[i].insn_mo->name, "sc")
+ || streq (history[i].insn_mo->name, "scd"))
+ {
+ unsigned long j;
+
+ for (j = i + 1; j < lookback; j++)
+ {
+ if (streq (history[i].insn_mo->name, "ll")
+ || streq (history[i].insn_mo->name, "lld"))
+ break;
+
+ if (delayed_branch_p (&history[j]))
+ {
+ if (streq (history[j].target, label_name))
+ {
+ add_fixed_insn (&sync_insn);
+ insert_into_history (0, 1, &sync_insn);
+ i = lookback;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* If we find a sc, we look forward to look for an branch insn,
+ and see whether it jump back and out of ll/sc. */
+ else if (streq(ip->insn_mo->name, "sc") || streq(ip->insn_mo->name, "scd"))
+ {
+ unsigned long lookback = ARRAY_SIZE (history) - 1;
+ unsigned long i;
+
+ for (i = 0; i < lookback; i++)
+ {
+ if (streq (history[i].insn_mo->name, "ll")
+ || streq (history[i].insn_mo->name, "lld"))
+ break;
+
+ if (delayed_branch_p (&history[i]))
+ {
+ unsigned long j;
+
+ for (j = i + 1; j < lookback; j++)
+ {
+ if (streq (history[j].insn_mo->name, "ll")
+ || streq (history[i].insn_mo->name, "lld"))
+ break;
+ }
+
+ for (; j < lookback; j++)
+ {
+ if (history[j].label[0] != '\0'
+ && streq (history[j].label, history[i].target)
+ && strcmp (history[j+1].insn_mo->name, "sync") != 0)
+ {
+ add_fixed_insn (&sync_insn);
+ insert_into_history (++j, 1, &sync_insn);
+ }
+ }
+ }
+ }
+ }
+
+ /* Skip if there is a sync before ll/lld. */
+ if ((strcmp (ip->insn_mo->name, "ll") == 0
+ || strcmp (ip->insn_mo->name, "lld") == 0)
+ && (strcmp (history[0].insn_mo->name, "sync") != 0))
+ {
+ add_fixed_insn (&sync_insn);
+ insert_into_history (0, 1, &sync_insn);
+ }
+}
+
/* IP is a branch that has a delay slot, and we need to fill it
automatically. Return true if we can do that by swapping IP
with the previous instruction.
&& insn_length (history) != 4)
return FALSE;
- /* On R5900 short loops need to be fixed by inserting a nop in
- the branch delay slots.
- A short loop can be terminated too early. */
- if (mips_opts.arch == CPU_R5900
+ /* On the R5900 short loops need to be fixed by inserting a NOP in the
+ branch delay slot.
+
+ The short loop bug under certain conditions causes loops to execute
+ only once or twice. We must ensure that the assembler never
+ generates loops that satisfy all of the following conditions:
+
+ - a loop consists of less than or equal to six instructions
+ (including the branch delay slot);
+ - a loop contains only one conditional branch instruction at the end
+ of the loop;
+ - a loop does not contain any other branch or jump instructions;
+ - a branch delay slot of the loop is not NOP (EE 2.9 or later).
+
+ We need to do this because of a hardware bug in the R5900 chip. */
+ if (mips_fix_r5900
/* Check if instruction has a parameter, ignore "j $31". */
&& (address_expr != NULL)
/* Parameter must be 16 bit. */
|| (ip->insn_opcode & 0xffff0000) == 0x04110000)) /* bgezal $0 */
{
int distance;
- /* Check if loop is shorter than 6 instructions including
- branch and delay slot. */
+ /* Check if loop is shorter than or equal to 6 instructions
+ including branch and delay slot. */
distance = frag_now_fix () - S_GET_VALUE (address_expr->X_add_symbol);
if (distance <= 20)
{
break;
}
}
- if (rv == FALSE)
+ if (!rv)
{
/* Insert nop after branch to fix short loop. */
return FALSE;
if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
fix_loongson2f (ip);
+ ip->target[0] = '\0';
+ if (offset_expr.X_op == O_symbol)
+ strncpy (ip->target, S_GET_NAME (offset_expr.X_add_symbol), 15);
+ ip->label[0] = '\0';
+ if (seg_info (now_seg)->label_list)
+ strncpy (ip->label, S_GET_NAME (seg_info (now_seg)->label_list->label), 15);
+ if (mips_fix_loongson3_llsc && !HAVE_CODE_COMPRESSION)
+ fix_loongson3_llsc (ip);
+
file_ase_mips16 |= mips_opts.mips16;
file_ase_micromips |= mips_opts.micromips;
add_relaxed_insn (ip, 12, 0,
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
+ mips_opts.ase & ASE_MIPS16E2,
mips_pic != NO_PIC,
HAVE_32BIT_SYMBOLS,
mips_opts.warn_about_macros,
{
if (required_insn_length == 2)
set_insn_error (0, _("invalid unextended operand value"));
- else
+ else if (!mips_opcode_32bit_p (opcode))
{
forced_insn_length = 4;
insn->insn_opcode |= MIPS16_EXTEND;
case 'A':
case 'B':
case 'E':
+ case 'V':
+ case 'u':
relax_char = c;
break;
|| *r == BFD_RELOC_MIPS_HIGHER
|| *r == BFD_RELOC_HI16_S
|| *r == BFD_RELOC_LO16
- || *r == BFD_RELOC_MIPS_GOT_OFST);
+ || *r == BFD_RELOC_MIPS_GOT_OFST
+ || (mips_opts.micromips
+ && (*r == BFD_RELOC_16
+ || *r == BFD_RELOC_MIPS_GOT16
+ || *r == BFD_RELOC_MIPS_CALL16
+ || *r == BFD_RELOC_MIPS_GOT_HI16
+ || *r == BFD_RELOC_MIPS_GOT_LO16
+ || *r == BFD_RELOC_MIPS_CALL_HI16
+ || *r == BFD_RELOC_MIPS_CALL_LO16
+ || *r == BFD_RELOC_MIPS_SUB
+ || *r == BFD_RELOC_MIPS_GOT_PAGE
+ || *r == BFD_RELOC_MIPS_HIGHEST
+ || *r == BFD_RELOC_MIPS_GOT_DISP
+ || *r == BFD_RELOC_MIPS_TLS_GD
+ || *r == BFD_RELOC_MIPS_TLS_LDM
+ || *r == BFD_RELOC_MIPS_TLS_DTPREL_HI16
+ || *r == BFD_RELOC_MIPS_TLS_DTPREL_LO16
+ || *r == BFD_RELOC_MIPS_TLS_GOTTPREL
+ || *r == BFD_RELOC_MIPS_TLS_TPREL_HI16
+ || *r == BFD_RELOC_MIPS_TLS_TPREL_LO16)));
break;
case 'o':
int imm = 0;
int ust = 0;
int lp = 0;
+ int ll_sc_paired = 0;
bfd_boolean large_offset;
int off;
int hold_mips_optimize;
case M_ADD_I:
s = "addi";
s2 = "add";
- goto do_addi;
+ if (ISA_IS_R6 (mips_opts.isa))
+ goto do_addi_i;
+ else
+ goto do_addi;
case M_ADDU_I:
s = "addiu";
s2 = "addu";
dbl = 1;
s = "daddi";
s2 = "dadd";
- if (!mips_opts.micromips)
+ if (!mips_opts.micromips && !ISA_IS_R6 (mips_opts.isa))
goto do_addi;
if (imm_expr.X_add_number >= -0x200
- && imm_expr.X_add_number < 0x200)
+ && imm_expr.X_add_number < 0x200
+ && !ISA_IS_R6 (mips_opts.isa))
{
macro_build (NULL, s, "t,r,.", op[0], op[1],
(int) imm_expr.X_add_number);
break;
}
++imm_expr.X_add_number;
- /* FALLTHROUGH */
+ /* Fall through. */
case M_BGE_I:
case M_BGEL_I:
if (mask == M_BGEL_I)
if (imm_expr.X_add_number <= GPR_SMIN)
{
do_true:
- /* result is always true */
+ /* Result is always true. */
as_warn (_("branch %s is always true"), ip->insn_mo->name);
macro_build (&offset_expr, "b", "p");
break;
&& imm_expr.X_add_number == -1))
goto do_false;
++imm_expr.X_add_number;
- /* FALLTHROUGH */
+ /* Fall through. */
case M_BGEU_I:
case M_BGEUL_I:
if (mask == M_BGEUL_I)
if (imm_expr.X_add_number >= GPR_SMAX)
goto do_true;
++imm_expr.X_add_number;
- /* FALLTHROUGH */
+ /* Fall through. */
case M_BLT_I:
case M_BLTL_I:
if (mask == M_BLTL_I)
&& imm_expr.X_add_number == -1))
goto do_true;
++imm_expr.X_add_number;
- /* FALLTHROUGH */
+ /* Fall through. */
case M_BLTU_I:
case M_BLTUL_I:
if (mask == M_BLTUL_I)
offbits = 12;
lp = 1;
goto ld;
+ case M_LLDP_AB:
+ case M_LLWP_AB:
+ case M_LLWPE_AB:
+ s = ip->insn_mo->name;
+ fmt = "t,d,s";
+ ll_sc_paired = 1;
+ offbits = 0;
+ goto ld;
case M_LWM_AB:
gas_assert (mips_opts.micromips);
s = "lwm";
goto ld_st;
ld:
- /* We don't want to use $0 as tempreg. */
- if (op[2] == op[0] + lp || op[0] + lp == ZERO)
- goto ld_st;
+ /* Try to use one the the load registers to compute the base address.
+ We don't want to use $0 as tempreg. */
+ if (ll_sc_paired)
+ {
+ if ((op[0] == ZERO && op[3] == op[1])
+ || (op[1] == ZERO && op[3] == op[0])
+ || (op[0] == ZERO && op[1] == ZERO))
+ goto ld_st;
+ else if (op[0] != op[3] && op[0] != ZERO)
+ tempreg = op[0];
+ else
+ tempreg = op[1];
+ }
else
- tempreg = op[0] + lp;
+ {
+ if (op[2] == op[0] + lp || op[0] + lp == ZERO)
+ goto ld_st;
+ else
+ tempreg = op[0] + lp;
+ }
goto ld_noat;
case M_SB_AB:
: ISA_IS_R6 (mips_opts.isa) ? 9
: 16);
goto ld_st;
+ case M_SCDP_AB:
+ case M_SCWP_AB:
+ case M_SCWPE_AB:
+ s = ip->insn_mo->name;
+ fmt = "t,d,s";
+ ll_sc_paired = 1;
+ offbits = 0;
+ goto ld_st;
case M_CACHE_AB:
s = "cache";
fmt = (mips_opts.micromips ? "k,~(b)"
ld_st:
tempreg = AT;
ld_noat:
- breg = op[2];
+ breg = ll_sc_paired ? op[3] : op[2];
if (small_offset_p (0, align, 16))
{
/* The first case exists for M_LD_AB and M_SD_AB, which are
else if (small_offset_p (0, align, offbits))
{
if (offbits == 0)
- macro_build (NULL, s, fmt, op[0], breg);
+ {
+ if (ll_sc_paired)
+ macro_build (NULL, s, fmt, op[0], op[1], breg);
+ else
+ macro_build (NULL, s, fmt, op[0], breg);
+ }
else
macro_build (NULL, s, fmt, op[0],
(int) offset_expr.X_add_number, breg);
tempreg, breg, -1, offset_reloc[0],
offset_reloc[1], offset_reloc[2]);
if (offbits == 0)
- macro_build (NULL, s, fmt, op[0], tempreg);
+ {
+ if (ll_sc_paired)
+ macro_build (NULL, s, fmt, op[0], op[1], tempreg);
+ else
+ macro_build (NULL, s, fmt, op[0], tempreg);
+ }
else
macro_build (NULL, s, fmt, op[0], 0, tempreg);
}
if (offset_expr.X_add_number != 0)
macro_build (&offset_expr, ADDRESS_ADDI_INSN,
"t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
- macro_build (NULL, s, fmt, op[0], tempreg);
+ if (ll_sc_paired)
+ macro_build (NULL, s, fmt, op[0], op[1], tempreg);
+ else
+ macro_build (NULL, s, fmt, op[0], tempreg);
}
else if (offbits == 16)
macro_build (&offset_expr, s, fmt, op[0], BFD_RELOC_LO16, tempreg);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
tempreg, tempreg, breg);
if (offbits == 0)
- macro_build (NULL, s, fmt, op[0], tempreg);
+ {
+ if (ll_sc_paired)
+ macro_build (NULL, s, fmt, op[0], op[1], tempreg);
+ else
+ macro_build (NULL, s, fmt, op[0], tempreg);
+ }
else
macro_build (NULL, s, fmt, op[0], 0, tempreg);
}
OFFSET_EXPR. */
if (imm_expr.X_op == O_constant)
{
- used_at = 1;
- load_register (AT, &imm_expr, FPR_SIZE == 64);
+ tempreg = ZERO;
+ if (((FPR_SIZE == 64 && GPR_SIZE == 64)
+ || !ISA_HAS_MXHC1 (mips_opts.isa))
+ && imm_expr.X_add_number != 0)
+ {
+ used_at = 1;
+ tempreg = AT;
+ load_register (AT, &imm_expr, FPR_SIZE == 64);
+ }
if (FPR_SIZE == 64 && GPR_SIZE == 64)
- macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
+ macro_build (NULL, "dmtc1", "t,S", tempreg, op[0]);
else
{
- if (ISA_HAS_MXHC1 (mips_opts.isa))
- macro_build (NULL, "mthc1", "t,G", AT, op[0]);
- else if (FPR_SIZE != 32)
- as_bad (_("Unable to generate `%s' compliant code "
- "without mthc1"),
- (FPR_SIZE == 64) ? "fp64" : "fpxx");
- else
- macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
+ if (!ISA_HAS_MXHC1 (mips_opts.isa))
+ {
+ if (FPR_SIZE != 32)
+ as_bad (_("Unable to generate `%s' compliant code "
+ "without mthc1"),
+ (FPR_SIZE == 64) ? "fp64" : "fpxx");
+ else
+ macro_build (NULL, "mtc1", "t,G", tempreg, op[0] + 1);
+ }
if (offset_expr.X_op == O_absent)
macro_build (NULL, "mtc1", "t,G", 0, op[0]);
else
load_register (AT, &offset_expr, 0);
macro_build (NULL, "mtc1", "t,G", AT, op[0]);
}
+ if (ISA_HAS_MXHC1 (mips_opts.isa))
+ {
+ if (imm_expr.X_add_number != 0)
+ {
+ used_at = 1;
+ tempreg = AT;
+ load_register (AT, &imm_expr, 0);
+ }
+ macro_build (NULL, "mthc1", "t,G", tempreg, op[0]);
+ }
}
break;
}
offset_reloc[2] = BFD_RELOC_UNUSED;
}
align = 8;
- /* Fall through */
+ /* Fall through. */
case M_L_DAB:
- /*
- * The MIPS assembler seems to check for X_add_number not
- * being double aligned and generating:
- * lui at,%hi(foo+1)
- * addu at,at,v1
- * addiu at,at,%lo(foo+1)
- * lwc1 f2,0(at)
- * lwc1 f3,4(at)
- * But, the resulting address is the same after relocation so why
- * generate the extra instruction?
- */
+ /* The MIPS assembler seems to check for X_add_number not
+ being double aligned and generating:
+ lui at,%hi(foo+1)
+ addu at,at,v1
+ addiu at,at,%lo(foo+1)
+ lwc1 f2,0(at)
+ lwc1 f3,4(at)
+ But, the resulting address is the same after relocation so why
+ generate the extra instruction? */
/* Itbl support may require additional care here. */
coproc = 1;
fmt = "T,o(b)";
macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SGE_I: /* X >= I <==> not (X < I) */
+ case M_SGE_I: /* X >= I <==> not (X < I). */
case M_SGEU_I:
if (imm_expr.X_add_number >= -0x8000
&& imm_expr.X_add_number < 0x8000)
macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
break;
- case M_SGT: /* X > Y <==> Y < X */
+ case M_SGT: /* X > Y <==> Y < X. */
s = "slt";
goto sgt;
case M_SGTU:
macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
break;
- case M_SGT_I: /* X > I <==> I < X */
+ case M_SGT_I: /* X > I <==> I < X. */
s = "slt";
goto sgti;
case M_SGTU_I:
macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
break;
- case M_SLE: /* X <= Y <==> Y >= X <==> not (Y < X) */
+ case M_SLE: /* X <= Y <==> Y >= X <==> not (Y < X). */
s = "slt";
goto sle;
case M_SLEU:
case M_SUB_I:
s = "addi";
s2 = "sub";
- goto do_subi;
+ if (ISA_IS_R6 (mips_opts.isa))
+ goto do_subi_i;
+ else
+ goto do_subi;
case M_SUBU_I:
s = "addiu";
s2 = "subu";
dbl = 1;
s = "daddi";
s2 = "dsub";
- if (!mips_opts.micromips)
+ if (!mips_opts.micromips && !ISA_IS_R6 (mips_opts.isa))
goto do_subi;
if (imm_expr.X_add_number > -0x200
- && imm_expr.X_add_number <= 0x200)
+ && imm_expr.X_add_number <= 0x200
+ && !ISA_IS_R6 (mips_opts.isa))
{
macro_build (NULL, s, "t,r,.", op[0], op[1],
(int) -imm_expr.X_add_number);
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')
+ else if (opend >= 2 && name[opend - 2] == '3' && name[opend - 1] == '2')
suffix = 4;
else
suffix = 0;
if (suffix)
{
- memcpy (name + opend - 2, name + opend, length - opend + 1);
+ memmove (name + opend - 2, name + opend, length - opend + 1);
insn = (struct mips_opcode *) hash_find (hash, name);
if (insn)
{
struct mips_operand_token *tokens;
unsigned int l;
- for (s = str; ISLOWER (*s); ++s)
+ for (s = str; *s != '\0' && *s != '.' && *s != ' '; ++s)
;
end = s;
c = *end;
break;
else if (*s++ == ' ')
break;
- /* Fall through. */
- default:
set_insn_error (0, _("unrecognized opcode"));
return;
}
mips16_immed_extend (offsetT val, unsigned int nbits)
{
int extval;
- if (nbits == 16)
+
+ extval = 0;
+ val &= (1U << nbits) - 1;
+ if (nbits == 16 || nbits == 9)
{
extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
val &= 0x1f;
extval = ((val >> 11) & 0xf) | (val & 0x7f0);
val &= 0xf;
}
- else
+ else if (nbits == 6)
{
extval = ((val & 0x1f) << 6) | (val & 0x20);
val = 0;
mips_fix_rm7000 = 0;
break;
+ case OPTION_FIX_LOONGSON3_LLSC:
+ mips_fix_loongson3_llsc = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON3_LLSC:
+ mips_fix_loongson3_llsc = FALSE;
+ break;
+
case OPTION_FIX_LOONGSON2F_JUMP:
mips_fix_loongson2f_jump = TRUE;
break;
mips_fix_cn63xxp1 = FALSE;
break;
+ case OPTION_FIX_R5900:
+ mips_fix_r5900 = TRUE;
+ mips_fix_r5900_explicit = TRUE;
+ break;
+
+ case OPTION_NO_FIX_R5900:
+ mips_fix_r5900 = FALSE;
+ mips_fix_r5900_explicit = TRUE;
+ break;
+
case OPTION_RELAX_BRANCH:
mips_relax_branch = 1;
break;
const struct mips_cpu_info *arch_info = 0;
const struct mips_cpu_info *tune_info = 0;
- /* GP relative stuff not working for PE */
+ /* GP relative stuff not working for PE. */
if (strncmp (TARGET_OS, "pe", 2) == 0)
{
if (g_switch_seen && g_switch_value != 0)
file_mips_opts.arch = arch_info->cpu;
file_mips_opts.isa = arch_info->isa;
+ file_mips_opts.init_ase = arch_info->ase;
+
+ /* The EVA Extension has instructions which are only valid when the R6 ISA
+ is enabled. This sets the ASE_EVA_R6 flag when both EVA and R6 ISA are
+ present. */
+ if (((file_mips_opts.ase & ASE_EVA) != 0) && ISA_IS_R6 (file_mips_opts.isa))
+ file_mips_opts.ase |= ASE_EVA_R6;
/* Set up initial mips_opts state. */
mips_opts = file_mips_opts;
+ /* For the R5900 default to `-mfix-r5900' unless the user told otherwise. */
+ if (!mips_fix_r5900_explicit)
+ mips_fix_r5900 = file_mips_opts.arch == CPU_R5900;
+
/* The register size inference code is now placed in
file_mips_check_options. */
void
mips_init_after_args (void)
{
- /* initialize opcodes */
+ /* Initialize opcodes. */
bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
}
md_pcrel_from (fixS *fixP)
{
valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
+
switch (fixP->fx_r_type)
{
case BFD_RELOC_MICROMIPS_7_PCREL_S1:
We accept BFD_RELOC_16_PCREL_S2 relocations against MIPS16 and microMIPS
symbols or BFD_RELOC_MICROMIPS_16_PCREL_S1 relocations against regular
MIPS symbols and associated with BAL instructions as these instructions
- may be be converted to JALX by the linker. */
+ may be converted to JALX by the linker. */
static bfd_boolean
fix_bad_cross_mode_branch_p (fixS *fixP)
return (val & 0x3) != isa_bit;
}
+/* Calculate the relocation target by masking off ISA mode bit before
+ combining symbol and addend. */
+
+static valueT
+fix_bad_misaligned_address (fixS *fixP)
+{
+ valueT val;
+ valueT off;
+ unsigned isa_mode;
+ gas_assert (fixP != NULL && fixP->fx_addsy != NULL);
+ val = S_GET_VALUE (fixP->fx_addsy);
+ off = fixP->fx_offset;
+ isa_mode = (ELF_ST_IS_COMPRESSED (S_GET_OTHER (fixP->fx_addsy))
+ ? 1 : 0);
+
+ return ((val & ~isa_mode) + off);
+}
+
/* Make the necessary checks on a regular MIPS branch pointed to by FIXP
and its calculated value VAL. */
else if (fix_bad_misaligned_branch_p (fixP))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS && (fixP->fx_offset & 0x3) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot encode misaligned addend "
else if (fix_bad_misaligned_jump_p (fixP, shift))
as_bad_where (fixP->fx_file, fixP->fx_line,
_("jump to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy)
- + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS
&& (fixP->fx_offset & ((1 << shift) - 1)) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
&& fixP->fx_done
&& fixP->fx_frag->fr_address >= text_section->vma
&& (fixP->fx_frag->fr_address
- < text_section->vma + bfd_get_section_size (text_section))
+ < text_section->vma + bfd_section_size (text_section))
&& ((insn & 0xffff0000) == 0x10000000 /* beq $0,$0 */
|| (insn & 0xffff0000) == 0x04010000 /* bgez $0 */
|| (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */
&& (fixP->fx_offset & 0x1) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("branch to misaligned address (0x%lx)"),
- (long) (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset));
+ (long) fix_bad_misaligned_address (fixP));
else if (HAVE_IN_PLACE_ADDENDS && (fixP->fx_offset & 0x1) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("cannot encode misaligned addend "
else
frag_align (to, fill ? *fill : 0, 0);
record_alignment (now_seg, to);
- mips_move_labels (labels, FALSE);
+ mips_move_labels (labels, subseg_text_p (now_seg));
}
/* Align to a given power of two. .align 0 turns off the automatic
case 'r':
seg = subseg_new (RDATA_SECTION_NAME,
(subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
- | SEC_READONLY | SEC_RELOC
- | SEC_DATA));
+ bfd_set_section_flags (seg, (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_RELOC | SEC_DATA));
if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
demand_empty_rest_of_line ();
case 's':
seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, seg,
+ bfd_set_section_flags (seg,
SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
case 'B':
seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
- bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
+ bfd_set_section_flags (seg, SEC_ALLOC);
if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
demand_empty_rest_of_line ();
char *name;
int c;
symbolS *symbolP;
- flagword flag;
do
{
*input_line_pointer = c;
SKIP_WHITESPACE_AFTER_NAME ();
- /* On Irix 5, every global symbol that is not explicitly labelled as
- being a function is apparently labelled as being an object. */
- flag = BSF_OBJECT;
-
if (!is_end_of_line[(unsigned char) *input_line_pointer]
&& (*input_line_pointer != ','))
{
(void) restore_line_pointer (c);
if (sec != NULL && (sec->flags & SEC_CODE) != 0)
- flag = BSF_FUNCTION;
+ symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
}
- symbol_get_bfdsym (symbolP)->flags |= flag;
-
c = *input_line_pointer;
if (c == ',')
{
demand_empty_rest_of_line ();
}
+#ifdef TE_IRIX
+/* The Irix 5 and 6 assemblers set the type of any common symbol and
+ any undefined non-function symbol to STT_OBJECT. We try to be
+ compatible, since newer Irix 5 and 6 linkers care. */
+
+void
+mips_frob_symbol (symbolS *symp ATTRIBUTE_UNUSED)
+{
+ /* This late in assembly we can set BSF_OBJECT indiscriminately
+ and let elf.c:swap_out_syms sort out the symbol type. */
+ flagword *flags = &symbol_get_bfdsym (symp)->flags;
+ if ((*flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+ || !S_IS_DEFINED (symp))
+ *flags |= BSF_OBJECT;
+}
+#endif
+
static void
s_option (int x ATTRIBUTE_UNUSED)
{
mips_opts.arch = p->cpu;
mips_opts.isa = p->isa;
isa_set = TRUE;
+ mips_opts.init_ase = p->ase;
}
}
else if (strncmp (name, "mips", 4) == 0)
mips_opts.arch = p->cpu;
mips_opts.isa = p->isa;
isa_set = TRUE;
+ mips_opts.init_ase = p->ase;
}
}
else
{
mips_opts.isa = file_mips_opts.isa;
mips_opts.arch = file_mips_opts.arch;
+ mips_opts.init_ase = file_mips_opts.init_ase;
mips_opts.gp = file_mips_opts.gp;
mips_opts.fp = file_mips_opts.fp;
}
static void
s_mips_stab (int type)
{
+ file_mips_check_options ();
mips_mark_labels ();
s_stab (type);
}
valueT
md_section_align (asection *seg, valueT addr)
{
- int align = bfd_get_section_alignment (stdoutput, seg);
+ int align = bfd_section_alignment (seg);
/* We don't need to align ELF sections to the full alignment.
However, Irix 5 may prefer that we align them at least to a 16
/* We don't want to modify the EXTENDED bit here; it might get us
into infinite loops. We change it only in mips_relax_frag(). */
if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
- return 12;
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
else
return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
}
if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
{
fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
- return -10;
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
}
else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
{
{
fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
- return -8;
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
}
else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
{
{
fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
- return 8;
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
}
else
{
fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
- return 10;
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
}
}
{
char *buf;
unsigned long insn;
- expressionS exp;
fixS *fixp;
buf = fragp->fr_literal + fragp->fr_fix;
/* We generate a fixup instead of applying it right now
because, if there are linker relaxations, we're going to
need the relocations. */
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
-
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
- BFD_RELOC_16_PCREL_S2);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ TRUE, BFD_RELOC_16_PCREL_S2);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* j or jal. */
insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
? 0x0c000000 : 0x08000000);
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
- FALSE, BFD_RELOC_MIPS_JMP);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MIPS_JMP);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
insn = HAVE_64BIT_ADDRESSES ? 0xdf800000 : 0x8f800000;
insn |= at << OP_SH_RT;
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
-
- if (fragp->fr_offset)
- {
- exp.X_add_symbol = make_expr_symbol (&exp);
- exp.X_add_number = 0;
- }
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
- FALSE, BFD_RELOC_MIPS_GOT16);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MIPS_GOT16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
insn |= at << OP_SH_RS | at << OP_SH_RT;
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
- FALSE, BFD_RELOC_LO16);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_LO16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
bfd_boolean short_ds;
unsigned long insn;
- expressionS exp;
fixS *fixp;
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
-
fragp->fr_fix += fragp->fr_var;
/* Handle 16-bit branches that fit or are forced to fit. */
/* We generate a fixup instead of applying it right now,
because if there is linker relaxation, we're going to
need the relocations. */
- if (type == 'D')
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
- BFD_RELOC_MICROMIPS_10_PCREL_S1);
- else if (type == 'E')
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
- BFD_RELOC_MICROMIPS_7_PCREL_S1);
- else
- abort ();
+ switch (type)
+ {
+ case 'D':
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 2,
+ fragp->fr_symbol, fragp->fr_offset,
+ TRUE, BFD_RELOC_MICROMIPS_10_PCREL_S1);
+ break;
+ case 'E':
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 2,
+ fragp->fr_symbol, fragp->fr_offset,
+ TRUE, BFD_RELOC_MICROMIPS_7_PCREL_S1);
+ break;
+ default:
+ abort ();
+ }
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* We generate a fixup instead of applying it right now,
because if there is linker relaxation, we're going to
need the relocations. */
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
- BFD_RELOC_MICROMIPS_16_PCREL_S1);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
/* j/jal/jals <sym> R_MICROMIPS_26_S1 */
insn = al ? jal : 0xd4000000;
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
- BFD_RELOC_MICROMIPS_JMP);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MICROMIPS_JMP);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
insn |= at << MICROMIPSOP_SH_RT;
- if (exp.X_add_number)
- {
- exp.X_add_symbol = make_expr_symbol (&exp);
- exp.X_add_number = 0;
- }
-
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
- BFD_RELOC_MICROMIPS_GOT16);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MICROMIPS_GOT16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
insn = HAVE_64BIT_ADDRESSES ? 0x5c000000 : 0x30000000;
insn |= at << MICROMIPSOP_SH_RT | at << MICROMIPSOP_SH_RS;
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
- BFD_RELOC_MICROMIPS_LO16);
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MICROMIPS_LO16);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
if (pcrel_op->include_isa_bit && !need_reloc)
{
- if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
+ if (!mips_ignore_branch_isa
+ && !ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
as_bad_where (fragp->fr_file, fragp->fr_line,
_("branch to a symbol in another ISA mode"));
else if ((fragp->fr_offset & 0x1) != 0)
as_bad_where (fragp->fr_file, fragp->fr_line,
_("branch to misaligned address (0x%lx)"),
- (long) val);
+ (long) (resolve_symbol_value (fragp->fr_symbol)
+ + (fragp->fr_offset & ~1)));
}
val = mips16_pcrel_val (fragp, pcrel_op, val, 0);
unsigned long reg;
unsigned long new;
unsigned long op;
+ bfd_boolean e2;
gas_assert (type == 'A' || type == 'B' || type == 'E');
gas_assert (RELAX_MIPS16_SYM32 (fragp->fr_subtype));
+ e2 = RELAX_MIPS16_E2 (fragp->fr_subtype);
+
if (need_reloc)
{
fixS *fixp;
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- fixp = fix_new (fragp, buf - fragp->fr_literal + 8, 4,
+ fixp = fix_new (fragp, buf - fragp->fr_literal + (e2 ? 4 : 8), 4,
fragp->fr_symbol, fragp->fr_offset,
FALSE, BFD_RELOC_MIPS16_LO16);
fixp->fx_file = fragp->fr_file;
abort ();
}
- new = 0xf0006800 | (reg << 8); /* LI */
+ new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8); /* LUI/LI */
new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
buf = write_compressed_insn (buf, new, 4);
- new = 0xf4003000 | (reg << 8) | (reg << 5); /* SLL */
- buf = write_compressed_insn (buf, new, 4);
+ if (!e2)
+ {
+ new = 0xf4003000 | (reg << 8) | (reg << 5); /* SLL */
+ buf = write_compressed_insn (buf, new, 4);
+ }
op |= mips16_immed_extend (val, 16);
buf = write_compressed_insn (buf, op, 4);
- fragp->fr_fix += 12;
+ fragp->fr_fix += e2 ? 8 : 12;
}
else
{
if (need_reloc)
{
bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
- expressionS exp;
fixS *fixp;
switch (type)
_("unsupported relocation"));
else if (ext)
{
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
-
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
- TRUE, reloc);
-
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ TRUE, reloc);
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
}
relax_substateT subtype = fragp->fr_subtype;
bfd_boolean second_longer = (subtype & RELAX_SECOND_LONGER) != 0;
bfd_boolean use_second = (subtype & RELAX_USE_SECOND) != 0;
- int first, second;
+ unsigned int first, second;
fixS *fixp;
first = RELAX_FIRST (subtype);
sequence instead. */
while (fixp
&& fixp->fx_frag == fragp
- && fixp->fx_where < fragp->fr_fix - second)
+ && fixp->fx_where + second < fragp->fr_fix)
{
if (subtype & RELAX_USE_SECOND)
fixp->fx_done = 1;
ext_ases |= AFL_ASE_MSA;
if (ase & ASE_XPA)
ext_ases |= AFL_ASE_XPA;
+ if (ase & ASE_MIPS16E2)
+ ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0;
+ if (ase & ASE_CRC)
+ ext_ases |= AFL_ASE_CRC;
+ if (ase & ASE_GINV)
+ ext_ases |= AFL_ASE_GINV;
+ if (ase & ASE_LOONGSON_MMI)
+ ext_ases |= AFL_ASE_LOONGSON_MMI;
+ if (ase & ASE_LOONGSON_CAM)
+ ext_ases |= AFL_ASE_LOONGSON_CAM;
+ if (ase & ASE_LOONGSON_EXT)
+ ext_ases |= AFL_ASE_LOONGSON_EXT;
+ if (ase & ASE_LOONGSON_EXT2)
+ ext_ases |= AFL_ASE_LOONGSON_EXT2;
return ext_ases;
}
else
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
}
- else if (mips_abi == N32_ABI)
- elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
- /* Nothing to do for N64_ABI. */
+ /* Nothing to do for N32_ABI or N64_ABI. */
if (mips_32bitmode)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
{
char *filename;
- filename = dwarf2_directive_file (0);
+ filename = dwarf2_directive_filename ();
/* Versions of GCC up to 3.1 start files with a ".file"
directive even for stabs output. Make sure that this
else
p = NULL;
- if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
+ if ((bfd_section_flags (now_seg) & SEC_CODE) == 0)
as_warn (_(".end not in text section"));
if (!cur_proc_ptr)
|| *input_line_pointer == '-')
get_number ();
- if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
+ if ((bfd_section_flags (now_seg) & SEC_CODE) == 0)
as_warn (_(".ent or .aent not in text section"));
if (!aent && cur_proc_ptr)
gcc's mips_cpu_info_table[]. */
static const struct mips_cpu_info mips_cpu_info_table[] =
{
- /* Entries for generic ISAs */
+ /* Entries for generic ISAs. */
{ "mips1", MIPS_CPU_IS_ISA, 0, ISA_MIPS1, CPU_R3000 },
{ "mips2", MIPS_CPU_IS_ISA, 0, ISA_MIPS2, CPU_R6000 },
{ "mips3", MIPS_CPU_IS_ISA, 0, ISA_MIPS3, CPU_R4000 },
{ "orion", 0, 0, ISA_MIPS3, CPU_R4600 },
{ "r4650", 0, 0, ISA_MIPS3, CPU_R4650 },
{ "r5900", 0, 0, ISA_MIPS3, CPU_R5900 },
- /* ST Microelectronics Loongson 2E and 2F cores */
+ /* ST Microelectronics Loongson 2E and 2F cores. */
{ "loongson2e", 0, 0, ISA_MIPS3, CPU_LOONGSON_2E },
- { "loongson2f", 0, 0, ISA_MIPS3, CPU_LOONGSON_2F },
+ { "loongson2f", 0, ASE_LOONGSON_MMI, ISA_MIPS3, CPU_LOONGSON_2F },
/* MIPS IV */
{ "r8000", 0, 0, ISA_MIPS4, CPU_R8000 },
{ "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 },
- /* interaptiv is the new name for 1004kf */
+ /* interaptiv is the new name for 1004kf. */
{ "interaptiv", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
- /* M5100 family */
+ { "interaptiv-mr2", 0,
+ ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
+ ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
+ /* M5100 family. */
{ "m5100", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },
{ "m5101", 0, ASE_MCU, ISA_MIPS32R5, CPU_MIPS32R5 },
/* P5600 with EVA and Virtualization ASEs, other ASEs are optional. */
{ "20kc", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
{ "25kf", 0, ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
- /* Broadcom SB-1 CPU core */
+ /* Broadcom SB-1 CPU core. */
{ "sb1", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
- /* Broadcom SB-1A CPU core */
+ /* Broadcom SB-1A CPU core. */
{ "sb1a", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
- { "loongson3a", 0, 0, ISA_MIPS64R2, CPU_LOONGSON_3A },
-
- /* MIPS 64 Release 2 */
-
- /* Cavium Networks Octeon CPU core */
+ /* MIPS 64 Release 2. */
+ /* Loongson CPU core. */
+ /* -march=loongson3a is an alias of -march=gs464 for compatibility. */
+ { "loongson3a", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
+ ISA_MIPS64R2, CPU_GS464 },
+ { "gs464", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
+ ISA_MIPS64R2, CPU_GS464 },
+ { "gs464e", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
+ | ASE_LOONGSON_EXT2, ISA_MIPS64R2, CPU_GS464E },
+ { "gs264e", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
+ | ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64, ISA_MIPS64R2, CPU_GS264E },
+
+ /* Cavium Networks Octeon CPU core. */
{ "octeon", 0, 0, ISA_MIPS64R2, CPU_OCTEON },
{ "octeon+", 0, 0, ISA_MIPS64R2, CPU_OCTEONP },
{ "octeon2", 0, 0, ISA_MIPS64R2, CPU_OCTEON2 },
MIPS64R2 rather than MIPS64. */
{ "xlp", 0, 0, ISA_MIPS64R2, CPU_XLR },
- /* MIPS 64 Release 6 */
- { "i6400", 0, ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
+ /* MIPS 64 Release 6. */
+ { "i6400", 0, ASE_VIRT | ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
+ { "i6500", 0, ASE_VIRT | ASE_MSA | ASE_CRC | ASE_GINV,
+ ISA_MIPS64R6, CPU_MIPS64R6},
{ "p6600", 0, ASE_VIRT | ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
- /* End marker */
+ /* End marker. */
{ NULL, 0, 0, 0, 0 }
};
-mips16 generate mips16 instructions\n\
-no-mips16 do not generate mips16 instructions\n"));
fprintf (stream, _("\
+-mmips16e2 generate MIPS16e2 instructions\n\
+-mno-mips16e2 do not generate MIPS16e2 instructions\n"));
+ fprintf (stream, _("\
-mmicromips generate microMIPS instructions\n\
-mno-micromips do not generate microMIPS instructions\n"));
fprintf (stream, _("\
-mvirt generate Virtualization instructions\n\
-mno-virt do not generate Virtualization instructions\n"));
fprintf (stream, _("\
+-mcrc generate CRC instructions\n\
+-mno-crc do not generate CRC instructions\n"));
+ fprintf (stream, _("\
+-mginv generate Global INValidate (GINV) instructions\n\
+-mno-ginv do not generate Global INValidate instructions\n"));
+ fprintf (stream, _("\
+-mloongson-mmi generate Loongson MultiMedia extensions Instructions (MMI) instructions\n\
+-mno-loongson-mmi do not generate Loongson MultiMedia extensions Instructions\n"));
+ fprintf (stream, _("\
+-mloongson-cam generate Loongson Content Address Memory (CAM) instructions\n\
+-mno-loongson-cam do not generate Loongson Content Address Memory Instructions\n"));
+ fprintf (stream, _("\
+-mloongson-ext generate Loongson EXTensions (EXT) instructions\n\
+-mno-loongson-ext do not generate Loongson EXTensions Instructions\n"));
+ fprintf (stream, _("\
+-mloongson-ext2 generate Loongson EXTensions R2 (EXT2) instructions\n\
+-mno-loongson-ext2 do not generate Loongson EXTensions R2 Instructions\n"));
+ fprintf (stream, _("\
-minsn32 only generate 32-bit microMIPS instructions\n\
-mno-insn32 generate all microMIPS instructions\n"));
+#if DEFAULT_MIPS_FIX_LOONGSON3_LLSC
+ fprintf (stream, _("\
+-mfix-loongson3-llsc work around Loongson3 LL/SC errata, default\n\
+-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata\n"));
+#else
+ fprintf (stream, _("\
+-mfix-loongson3-llsc work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata, default\n"));
+#endif
fprintf (stream, _("\
-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
+-mfix-loongson3-llsc work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc disable work around Loongson3 LL/SC errata\n\
-mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
-mfix-24k insert a nop after ERET and DERET instructions\n\
-mfix-cn63xxp1 work around CN63XXP1 PREF errata\n\
+-mfix-r5900 work around R5900 short loop errata\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-msym32 assume all symbols have 32-bit values\n\
--O0 remove unneeded NOPs, do not swap branches\n\
--O remove unneeded NOPs and swap branches\n\
+-O0 do not remove unneeded NOPs, do not swap branches\n\
+-O, -O1 remove unneeded NOPs, do not swap branches\n\
+-O2 remove unneeded NOPs and swap branches\n\
--trap, --no-break trap exception on div by 0 and mult overflow\n\
--break, --no-trap break exception on div by 0 and mult overflow\n"));
fprintf (stream, _("\
fputc ('\n', stream);
fprintf (stream, _("\
--32 create o32 ABI object file (default)\n\
--n32 create n32 ABI object file\n\
--64 create 64 ABI object file\n"));
+-32 create o32 ABI object file%s\n"),
+ MIPS_DEFAULT_ABI == O32_ABI ? _(" (default)") : "");
+ fprintf (stream, _("\
+-n32 create n32 ABI object file%s\n"),
+ MIPS_DEFAULT_ABI == N32_ABI ? _(" (default)") : "");
+ fprintf (stream, _("\
+-64 create 64 ABI object file%s\n"),
+ MIPS_DEFAULT_ABI == N64_ABI ? _(" (default)") : "");
}
#ifdef TE_IRIX