/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright (C) 1993-2017 Free Software Foundation, Inc.
+ Copyright (C) 1993-2018 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
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, small, ext, dslot, jal_dslot) \
+#define RELAX_MIPS16_ENCODE(type, e2, pic, sym32, nomacro, \
+ small, ext, \
+ dslot, jal_dslot) \
(0x80000000 \
| ((type) & 0xff) \
- | ((small) ? 0x100 : 0) \
- | ((ext) ? 0x200 : 0) \
- | ((dslot) ? 0x400 : 0) \
- | ((jal_dslot) ? 0x800 : 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_USER_SMALL(i) (((i) & 0x100) != 0)
-#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
-#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0)
-#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0)
-#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0)
-#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000)
-#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
-#define RELAX_MIPS16_ALWAYS_EXTENDED(i) (((i) & 0x2000) != 0)
-#define RELAX_MIPS16_MARK_ALWAYS_EXTENDED(i) ((i) | 0x2000)
-#define RELAX_MIPS16_CLEAR_ALWAYS_EXTENDED(i) ((i) & ~0x2000)
+#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_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_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},
/* Old-style architecture options. Don't add more of these. */
{"m4650", no_argument, NULL, OPTION_M4650},
{ "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 },
};
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);
+
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;
+ }
+
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. */
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 == '-'))
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
- in *VALUE. Use FALLBACK as the value if the match succeeded with an
- error. */
+ the tokens and return true on success, storing the constant value
+ in *VALUE. */
static bfd_boolean
match_const_int (struct mips_arg_info *arg, offsetT *value)
*value = ex.X_add_number;
else
{
- match_not_constant (arg);
+ if (r[0] == BFD_RELOC_UNUSED && ex.X_op == O_big)
+ match_out_of_range (arg);
+ else
+ match_not_constant (arg);
return FALSE;
}
return TRUE;
if (!match_expression (arg, &offset_expr, offset_reloc))
return FALSE;
+ if (offset_expr.X_op == O_big)
+ {
+ match_out_of_range (arg);
+ return FALSE;
+ }
+
if (offset_reloc[0] != BFD_RELOC_UNUSED)
/* Relocation operators were used. Accept the argument and
leave the relocation value in offset_expr and offset_relocs
/* Accept non-constant operands if no later alternative matches,
leaving it for the caller to process. */
if (!arg->lax_match)
- return FALSE;
+ {
+ match_not_constant (arg);
+ return FALSE;
+ }
offset_reloc[0] = BFD_RELOC_LO16;
return TRUE;
}
{
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 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:
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);
break;
}
}
- if (rv == FALSE)
+ if (!rv)
{
/* Insert nop after branch to fix short loop. */
return FALSE;
symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP);
offset = 0;
}
- add_relaxed_insn (ip, 4, 0,
+ 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,
require_unextended, require_extended,
delayed_branch_p (&history[0]),
history[0].mips16_absolute_jump_p),
{
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;
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))
+ if (!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;
+ {
+ match_not_constant (&arg);
+ return FALSE;
+ }
+
+ if (offset_expr.X_op == O_big)
+ {
+ match_out_of_range (&arg);
+ return FALSE;
+ }
relax_char = c;
continue;
|| *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':
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;
{"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
{"%got", BFD_RELOC_MIPS_GOT16},
{"%gp_rel", BFD_RELOC_GPREL16},
+ {"%gprel", BFD_RELOC_GPREL16},
{"%half", BFD_RELOC_16},
{"%highest", BFD_RELOC_MIPS_HIGHEST},
{"%higher", BFD_RELOC_MIPS_HIGHER},
static const struct percent_op_match mips16_percent_op[] =
{
{"%lo", BFD_RELOC_MIPS16_LO16},
+ {"%gp_rel", BFD_RELOC_MIPS16_GPREL},
{"%gprel", BFD_RELOC_MIPS16_GPREL},
{"%got", BFD_RELOC_MIPS16_GOT16},
{"%call16", BFD_RELOC_MIPS16_CALL16},
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)
static void
s_mips_stab (int type)
{
+ file_mips_check_options ();
mips_mark_labels ();
s_stab (type);
}
return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
}
+/* Given a MIPS16 variant frag FRAGP, return non-zero if it needs
+ macro expansion. SEC is the section the frag is in. We only
+ support PC-relative instructions (LA, DLA, LW, LD) here, in
+ non-PIC code using 32-bit addressing. */
+
+static int
+mips16_macro_frag (fragS *fragp, asection *sec, long stretch)
+{
+ const struct mips_pcrel_operand *pcrel_op;
+ const struct mips_int_operand *operand;
+ offsetT val;
+ segT symsec;
+ int type;
+
+ gas_assert (!RELAX_MIPS16_USER_SMALL (fragp->fr_subtype));
+
+ if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
+ return 0;
+ if (!RELAX_MIPS16_SYM32 (fragp->fr_subtype))
+ return 0;
+
+ type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
+ switch (type)
+ {
+ case 'A':
+ case 'B':
+ case 'E':
+ symsec = S_GET_SEGMENT (fragp->fr_symbol);
+ if (bfd_is_abs_section (symsec))
+ return 1;
+ if (RELAX_MIPS16_PIC (fragp->fr_subtype))
+ return 0;
+ if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) || sec != symsec)
+ return 1;
+
+ operand = mips16_immed_operand (type, TRUE);
+ val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ pcrel_op = (const struct mips_pcrel_operand *) operand;
+ val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
+
+ return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val);
+
+ default:
+ return 0;
+ }
+}
+
/* Compute the length of a branch sequence, and adjust the
RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the
worst-case length is computed, with UPDATE being used to indicate
}
if (RELAX_MIPS16_P (fragp->fr_subtype))
- /* 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(). */
- return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
+ {
+ /* 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 RELAX_MIPS16_E2 (fragp->fr_subtype) ? 8 : 12;
+ else
+ return RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2;
+ }
if (RELAX_MICROMIPS_P (fragp->fr_subtype))
{
if (! RELAX_MIPS16_P (fragp->fr_subtype))
return 0;
- if (mips16_extended_frag (fragp, sec, stretch))
+ if (!mips16_extended_frag (fragp, sec, stretch))
{
- if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -6 : -10;
+ }
+ else if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
+ return -2;
+ }
+ else
+ return 0;
+ }
+ else if (!mips16_macro_frag (fragp, sec, stretch))
+ {
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_CLEAR_MACRO (fragp->fr_subtype);
+ fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? -4 : -8;
+ }
+ else if (!RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ {
+ fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
+ return 2;
+ }
+ else
return 0;
- fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
- return 2;
}
else
{
- if (! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+ if (RELAX_MIPS16_MACRO (fragp->fr_subtype))
return 0;
- fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
- return -2;
+ 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 RELAX_MIPS16_E2 (fragp->fr_subtype) ? 4 : 8;
+ }
+ else
+ {
+ fragp->fr_subtype = RELAX_MIPS16_MARK_MACRO (fragp->fr_subtype);
+ return RELAX_MIPS16_E2 (fragp->fr_subtype) ? 6 : 10;
+ }
}
return 0;
{
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;
const struct mips_int_operand *operand;
offsetT val;
char *buf;
- unsigned int user_length, length;
+ unsigned int user_length;
bfd_boolean need_reloc;
unsigned long insn;
+ bfd_boolean mac;
bfd_boolean ext;
segT symsec;
type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
operand = mips16_immed_operand (type, FALSE);
+ mac = RELAX_MIPS16_MACRO (fragp->fr_subtype);
ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype);
val = resolve_symbol_value (fragp->fr_symbol) + fragp->fr_offset;
symsec = S_GET_SEGMENT (fragp->fr_symbol);
need_reloc = (S_FORCE_RELOC (fragp->fr_symbol, TRUE)
- || (operand->root.type == OP_PCREL
+ || (operand->root.type == OP_PCREL && !mac
? asec != symsec
: !bfd_is_abs_section (symsec)));
- if (operand->root.type == OP_PCREL)
+ if (operand->root.type == OP_PCREL && !mac)
{
const struct mips_pcrel_operand *pcrel_op;
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)
record_alignment (asec, operand->shift);
}
- if (ext
- && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
- || RELAX_MIPS16_DSLOT (fragp->fr_subtype)))
+ if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
+ || RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+ {
+ if (mac)
+ as_warn_where (fragp->fr_file, fragp->fr_line,
+ _("macro instruction expanded into multiple "
+ "instructions in a branch delay slot"));
+ else if (ext)
+ as_warn_where (fragp->fr_file, fragp->fr_line,
+ _("extended instruction in a branch delay slot"));
+ }
+ else if (RELAX_MIPS16_NOMACRO (fragp->fr_subtype) && mac)
as_warn_where (fragp->fr_file, fragp->fr_line,
- _("extended instruction in delay slot"));
+ _("macro instruction expanded into multiple "
+ "instructions"));
buf = fragp->fr_literal + fragp->fr_fix;
else
user_length = 0;
- if (need_reloc)
+ if (mac)
{
- bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
- expressionS exp;
- fixS *fixp;
+ unsigned long reg;
+ unsigned long new;
+ unsigned long op;
+ bfd_boolean e2;
- switch (type)
+ 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)
{
- case 'p':
- case 'q':
- reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+ fixS *fixp;
+
+ gas_assert (!RELAX_MIPS16_PIC (fragp->fr_subtype));
+
+ fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+ fragp->fr_symbol, fragp->fr_offset,
+ FALSE, BFD_RELOC_MIPS16_HI16_S);
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
+
+ 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;
+ fixp->fx_line = fragp->fr_line;
+
+ val = 0;
+ }
+
+ switch (insn & 0xf800)
+ {
+ case 0x0800: /* ADDIU */
+ reg = (insn >> 8) & 0x7;
+ op = 0xf0004800 | (reg << 8);
break;
- default:
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("unsupported relocation"));
+ case 0xb000: /* LW */
+ reg = (insn >> 8) & 0x7;
+ op = 0xf0009800 | (reg << 8) | (reg << 5);
break;
+ case 0xf800: /* I64 */
+ reg = (insn >> 5) & 0x7;
+ switch (insn & 0x0700)
+ {
+ case 0x0400: /* LD */
+ op = 0xf0003800 | (reg << 8) | (reg << 5);
+ break;
+ case 0x0600: /* DADDIU */
+ op = 0xf000fd00 | (reg << 5);
+ break;
+ default:
+ abort ();
+ }
+ break;
+ default:
+ abort ();
}
- if (reloc == BFD_RELOC_NONE)
- ;
- else if (ext)
+
+ new = (e2 ? 0xf0006820 : 0xf0006800) | (reg << 8); /* LUI/LI */
+ new |= mips16_immed_extend ((val + 0x8000) >> 16, 16);
+ buf = write_compressed_insn (buf, new, 4);
+ if (!e2)
{
- exp.X_op = O_symbol;
- exp.X_add_symbol = fragp->fr_symbol;
- exp.X_add_number = fragp->fr_offset;
+ 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);
- fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
- TRUE, reloc);
+ fragp->fr_fix += e2 ? 8 : 12;
+ }
+ else
+ {
+ unsigned int length = ext ? 4 : 2;
- fixp->fx_file = fragp->fr_file;
- fixp->fx_line = fragp->fr_line;
+ if (need_reloc)
+ {
+ bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
+ fixS *fixp;
+
+ switch (type)
+ {
+ case 'p':
+ case 'q':
+ reloc = BFD_RELOC_MIPS16_16_PCREL_S1;
+ break;
+ default:
+ break;
+ }
+ if (mac || reloc == BFD_RELOC_NONE)
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("unsupported relocation"));
+ else if (ext)
+ {
+ 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;
+ }
+ else
+ as_bad_where (fragp->fr_file, fragp->fr_line,
+ _("invalid unextended operand value"));
}
else
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("invalid unextended operand value"));
- }
- else
- mips16_immed (fragp->fr_file, fragp->fr_line, type,
- BFD_RELOC_UNUSED, val, user_length, &insn);
+ mips16_immed (fragp->fr_file, fragp->fr_line, type,
+ BFD_RELOC_UNUSED, val, user_length, &insn);
- length = (ext ? 4 : 2);
- gas_assert (mips16_opcode_length (insn) == length);
- write_compressed_insn (buf, insn, length);
- fragp->fr_fix += length;
+ gas_assert (mips16_opcode_length (insn) == length);
+ write_compressed_insn (buf, insn, length);
+ fragp->fr_fix += length;
+ }
}
else
{
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;
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
{ "r5900", 0, 0, ISA_MIPS3, CPU_R5900 },
/* 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 },
{ "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
/* interaptiv is the new name for 1004kf */
{ "interaptiv", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "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 },
/* 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 */
+ /* Loongson CPU core */
+ { "loongson3a", 0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM, ISA_MIPS64R2,
+ CPU_LOONGSON_3A },
/* Cavium Networks Octeon CPU core */
{ "octeon", 0, 0, ISA_MIPS64R2, CPU_OCTEON },
-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, _("\
-minsn32 only generate 32-bit microMIPS instructions\n\
-mno-insn32 generate all microMIPS instructions\n"));
fprintf (stream, _("\
-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