/* tc-mips.c -- assemble code for a MIPS chip.
- Copyright (C) 1993-2014 Free Software Foundation, Inc.
+ Copyright (C) 1993-2016 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
/* Specifies whether module level options have been checked yet. */
static bfd_boolean file_mips_opts_checked = FALSE;
-/* True if -mnan=2008, false if -mnan=legacy. */
-static bfd_boolean mips_flag_nan2008 = FALSE;
+/* Do we support nan2008? 0 if we don't, 1 if we do, and -1 if the
+ value has not been initialized. Changed by `.nan legacy' and
+ `.nan 2008', and the -mnan=legacy and -mnan=2008 command line
+ options, and the default CPU. */
+static int mips_nan2008 = -1;
/* This is the struct we use to hold the module level set of options.
Note that we must set the isa field to ISA_UNKNOWN and the ASE, gp and
/* Likewise 64-bit registers. */
#define ABI_NEEDS_64BIT_REGS(ABI) \
- ((ABI) == N32_ABI \
+ ((ABI) == N32_ABI \
|| (ABI) == N64_ABI \
|| (ABI) == O64_ABI)
+#define ISA_IS_R6(ISA) \
+ ((ISA) == ISA_MIPS32R6 \
+ || (ISA) == ISA_MIPS64R6)
+
/* Return true if ISA supports 64 bit wide gp registers. */
#define ISA_HAS_64BIT_REGS(ISA) \
((ISA) == ISA_MIPS3 \
|| (ISA) == ISA_MIPS64 \
|| (ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
- || (ISA) == ISA_MIPS64R5)
+ || (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6)
/* Return true if ISA supports 64 bit wide float registers. */
#define ISA_HAS_64BIT_FPRS(ISA) \
|| (ISA) == ISA_MIPS32R2 \
|| (ISA) == ISA_MIPS32R3 \
|| (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS32R6 \
|| (ISA) == ISA_MIPS64 \
|| (ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
- || (ISA) == ISA_MIPS64R5 )
+ || (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6)
/* Return true if ISA supports 64-bit right rotate (dror et al.)
instructions. */
((ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
|| (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6 \
|| (mips_opts.micromips \
&& ISA_HAS_64BIT_REGS (ISA)) \
)
((ISA) == ISA_MIPS32R2 \
|| (ISA) == ISA_MIPS32R3 \
|| (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS32R6 \
|| (ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
|| (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6 \
|| (mips_opts.ase & ASE_SMARTMIPS) \
|| mips_opts.micromips \
)
|| (ISA) == ISA_MIPS32R2 \
|| (ISA) == ISA_MIPS32R3 \
|| (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS32R6 \
|| (ISA) == ISA_MIPS64 \
|| (ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
|| (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6 \
|| (CPU) == CPU_R5900) \
&& (CPU) != CPU_LOONGSON_3A)
((ISA) == ISA_MIPS32R2 \
|| (ISA) == ISA_MIPS32R3 \
|| (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS32R6 \
+ || (ISA) == ISA_MIPS64R2 \
+ || (ISA) == ISA_MIPS64R3 \
+ || (ISA) == ISA_MIPS64R5 \
+ || (ISA) == ISA_MIPS64R6)
+
+/* Return true if ISA supports legacy NAN. */
+#define ISA_HAS_LEGACY_NAN(ISA) \
+ ((ISA) == ISA_MIPS1 \
+ || (ISA) == ISA_MIPS2 \
+ || (ISA) == ISA_MIPS3 \
+ || (ISA) == ISA_MIPS4 \
+ || (ISA) == ISA_MIPS5 \
+ || (ISA) == ISA_MIPS32 \
+ || (ISA) == ISA_MIPS32R2 \
+ || (ISA) == ISA_MIPS32R3 \
+ || (ISA) == ISA_MIPS32R5 \
+ || (ISA) == ISA_MIPS64 \
|| (ISA) == ISA_MIPS64R2 \
|| (ISA) == ISA_MIPS64R3 \
|| (ISA) == ISA_MIPS64R5)
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
/* True if CPU is in the Octeon family */
-#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP || (CPU) == CPU_OCTEON2)
+#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
+ || (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
/* True if CPU has seq/sne and seqi/snei instructions. */
#define CPU_HAS_SEQ(CPU) (CPU_IS_OCTEON (CPU))
|| mips_opts.isa == ISA_MIPS32R2 \
|| mips_opts.isa == ISA_MIPS32R3 \
|| mips_opts.isa == ISA_MIPS32R5 \
+ || mips_opts.isa == ISA_MIPS32R6 \
|| mips_opts.isa == ISA_MIPS64 \
|| mips_opts.isa == ISA_MIPS64R2 \
|| mips_opts.isa == ISA_MIPS64R3 \
|| mips_opts.isa == ISA_MIPS64R5 \
+ || mips_opts.isa == ISA_MIPS64R6 \
|| mips_opts.arch == CPU_R4010 \
|| mips_opts.arch == CPU_R5900 \
|| mips_opts.arch == CPU_R10000 \
/* Branch without likely bit. If label is out of range, we turn:
- beq reg1, reg2, label
+ beq reg1, reg2, label
delay slot
into
static void mips_ip (char *str, struct mips_cl_insn * ip);
static void mips16_ip (char *str, struct mips_cl_insn * ip);
static void mips16_immed
- (char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
+ (const char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
unsigned int, unsigned long *);
static size_t my_getSmallExpression
(expressionS *, bfd_reloc_code_real_type *, char *);
OPTION_MIPS32R2,
OPTION_MIPS32R3,
OPTION_MIPS32R5,
+ OPTION_MIPS32R6,
OPTION_MIPS64R2,
OPTION_MIPS64R3,
OPTION_MIPS64R5,
+ OPTION_MIPS64R6,
OPTION_MIPS16,
OPTION_NO_MIPS16,
OPTION_MIPS3D,
OPTION_NO_SMARTMIPS,
OPTION_DSPR2,
OPTION_NO_DSPR2,
+ OPTION_DSPR3,
+ OPTION_NO_DSPR3,
OPTION_EVA,
OPTION_NO_EVA,
OPTION_XPA,
{"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
{"mips32r3", no_argument, NULL, OPTION_MIPS32R3},
{"mips32r5", no_argument, NULL, OPTION_MIPS32R5},
+ {"mips32r6", no_argument, NULL, OPTION_MIPS32R6},
{"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
{"mips64r3", no_argument, NULL, OPTION_MIPS64R3},
{"mips64r5", no_argument, NULL, OPTION_MIPS64R5},
+ {"mips64r6", no_argument, NULL, OPTION_MIPS64R6},
/* Options which specify Application Specific Extensions (ASEs). */
{"mips16", no_argument, NULL, OPTION_MIPS16},
{"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
{"mdspr2", no_argument, NULL, OPTION_DSPR2},
{"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
+ {"mdspr3", no_argument, NULL, OPTION_DSPR3},
+ {"mno-dspr3", no_argument, NULL, OPTION_NO_DSPR3},
{"meva", no_argument, NULL, OPTION_EVA},
{"mno-eva", no_argument, NULL, OPTION_NO_EVA},
{"mmicromips", no_argument, NULL, OPTION_MICROMIPS},
int mips64_rev;
int micromips32_rev;
int micromips64_rev;
+
+ /* The architecture where the ASE was removed or -1 if the extension has not
+ been removed. */
+ int rem_rev;
};
/* A table of all supported ASEs. */
static const struct mips_ase mips_ases[] = {
{ "dsp", ASE_DSP, ASE_DSP64,
OPTION_DSP, OPTION_NO_DSP,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
{ "dspr2", ASE_DSP | ASE_DSPR2, 0,
OPTION_DSPR2, OPTION_NO_DSPR2,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
+
+ { "dspr3", ASE_DSP | ASE_DSPR2 | ASE_DSPR3, 0,
+ OPTION_DSPR3, OPTION_NO_DSPR3,
+ 6, 6, -1, -1,
+ -1 },
{ "eva", ASE_EVA, 0,
OPTION_EVA, OPTION_NO_EVA,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
{ "mcu", ASE_MCU, 0,
OPTION_MCU, OPTION_NO_MCU,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
/* Deprecated in MIPS64r5, but we don't implement that yet. */
{ "mdmx", ASE_MDMX, 0,
OPTION_MDMX, OPTION_NO_MDMX,
- -1, 1, -1, -1 },
+ -1, 1, -1, -1,
+ 6 },
/* Requires 64-bit FPRs, so the minimum MIPS32 revision is 2. */
{ "mips3d", ASE_MIPS3D, 0,
OPTION_MIPS3D, OPTION_NO_MIPS3D,
- 2, 1, -1, -1 },
+ 2, 1, -1, -1,
+ 6 },
{ "mt", ASE_MT, 0,
OPTION_MT, OPTION_NO_MT,
- 2, 2, -1, -1 },
+ 2, 2, -1, -1,
+ -1 },
{ "smartmips", ASE_SMARTMIPS, 0,
OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS,
- 1, -1, -1, -1 },
+ 1, -1, -1, -1,
+ 6 },
{ "virt", ASE_VIRT, ASE_VIRT64,
OPTION_VIRT, OPTION_NO_VIRT,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
{ "msa", ASE_MSA, ASE_MSA64,
OPTION_MSA, OPTION_NO_MSA,
- 2, 2, 2, 2 },
+ 2, 2, 2, 2,
+ -1 },
{ "xpa", ASE_XPA, 0,
OPTION_XPA, OPTION_NO_XPA,
- 2, 2, -1, -1 }
+ 2, 2, -1, -1,
+ -1 },
};
/* The set of ASEs that require -mfp64. */
/* Groups of ASE_* flags that represent different revisions of an ASE. */
static const unsigned int mips_ase_groups[] = {
- ASE_DSP | ASE_DSPR2
+ ASE_DSP | ASE_DSPR2 | ASE_DSPR3
};
\f
/* Pseudo-op table.
static inline void
mips_clear_insn_labels (void)
{
- register struct insn_label_list **pl;
+ struct insn_label_list **pl;
segment_info_type *si;
if (now_seg)
{
for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
;
-
+
si = seg_info (now_seg);
*pl = si->label_list;
si->label_list = NULL;
if (mips_opts.isa == ISA_MIPS32R5 || mips_opts.isa == ISA_MIPS64R5)
return 5;
+ if (mips_opts.isa == ISA_MIPS32R6 || mips_opts.isa == ISA_MIPS64R6)
+ return 6;
+
/* microMIPS implies revision 2 or above. */
if (mips_opts.micromips)
return 2;
as_warn (_("the `%s' extension requires %s%d revision %d or greater"),
ase->name, base, size, min_rev);
}
+ else if ((ase->rem_rev > 0 && mips_isa_rev () >= ase->rem_rev)
+ && (warned_isa & ase->flags) != ase->flags)
+ {
+ warned_isa |= ase->flags;
+ base = mips_opts.micromips ? "microMIPS" : "MIPS";
+ size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
+ as_warn (_("the `%s' extension was removed in %s%d revision %d"),
+ ase->name, base, size, ase->rem_rev);
+ }
+
if ((ase->flags & FP64_ASES)
&& mips_opts.fp != 64
&& (warned_fp32 & ase->flags) != ase->flags)
}
/* Return the length of a microMIPS instruction in bytes. If bits of
- the mask beyond the low 16 are 0, then it is a 16-bit instruction.
- Otherwise assume a 32-bit instruction; 48-bit instructions (0x1f
- major opcode) will require further modifications to the opcode
- table. */
+ the mask beyond the low 16 are 0, then it is a 16-bit instruction,
+ otherwise it is a 32-bit instruction. */
static inline unsigned int
micromips_insn_length (const struct mips_opcode *mo)
static void
report_insn_error (const char *str)
{
- const char *msg;
+ const char *msg = concat (insn_error.msg, " `%s'", NULL);
- msg = ACONCAT ((insn_error.msg, " `%s'", NULL));
switch (insn_error.format)
{
case ERR_FMT_PLAIN:
as_bad (msg, insn_error.u.ss[0], insn_error.u.ss[1], str);
break;
}
+
+ free ((char *) msg);
}
/* Initialize vr4120_conflicts. There is a bit of duplication here:
{"$28", RTYPE_NUM | 28}, \
{"$29", RTYPE_NUM | 29}, \
{"$30", RTYPE_NUM | 30}, \
- {"$31", RTYPE_NUM | 31}
+ {"$31", RTYPE_NUM | 31}
#define FPU_REGISTER_NAMES \
{"$f0", RTYPE_FPU | 0}, \
{"$ta0", RTYPE_GP | 12}, /* alias for $t4 */ \
{"$ta1", RTYPE_GP | 13}, /* alias for $t5 */ \
{"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \
- {"$ta3", RTYPE_GP | 15} /* alias for $t7 */
+ {"$ta3", RTYPE_GP | 15} /* alias for $t7 */
/* Remaining symbolic register names */
#define SYMBOLIC_REGISTER_NAMES \
/* The $txx registers depends on the abi,
these will be added later into the symbol table from
- one of the tables below once mips_abi is set after
+ one of the tables below once mips_abi is set after
parsing of arguments from the command line. */
SYMBOLIC_REGISTER_NAMES,
static char *
mips_parse_argument_token (char *s, char float_format)
{
- char *end, *save_in, *err;
+ char *end, *save_in;
+ const char *err;
unsigned int regno1, regno2, channels;
struct mips_operand_token token;
used_bits &= ~(mask & 0x700);
}
/* Skip prefix characters. */
- if (decode_operand && (*s == '+' || *s == 'm'))
+ if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
++s;
opno += 1;
break;
as_bad (_("-G may not be used in position-independent code"));
g_switch_value = 0;
}
+ else if (mips_abicalls)
+ {
+ if (g_switch_seen && g_switch_value != 0)
+ as_bad (_("-G may not be used with abicalls"));
+ g_switch_value = 0;
+ }
if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
as_warn (_("could not set architecture and machine"));
/* We add all the general register names to the symbol table. This
helps us detect invalid uses of them. */
- for (i = 0; reg_names[i].name; i++)
+ for (i = 0; reg_names[i].name; i++)
symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
reg_names[i].num, /* & RNUM_MASK, */
&zero_address_frag));
if (HAVE_NEWABI)
- for (i = 0; reg_names_n32n64[i].name; i++)
+ for (i = 0; reg_names_n32n64[i].name; i++)
symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
reg_names_n32n64[i].num, /* & RNUM_MASK, */
&zero_address_frag));
else
- for (i = 0; reg_names_o32[i].name; i++)
+ for (i = 0; reg_names_o32[i].name; i++)
symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
reg_names_o32[i].num, /* & RNUM_MASK, */
&zero_address_frag));
for (i = 0; i < 32; i++)
{
- char regname[7];
+ char regname[6];
/* R5900 VU0 floating-point register. */
- regname[sizeof (rename) - 1] = 0;
- snprintf (regname, sizeof (regname) - 1, "$vf%d", i);
+ sprintf (regname, "$vf%d", i);
symbol_table_insert (symbol_new (regname, reg_section,
RTYPE_VF | i, &zero_address_frag));
/* R5900 VU0 integer register. */
- snprintf (regname, sizeof (regname) - 1, "$vi%d", i);
+ sprintf (regname, "$vi%d", i);
symbol_table_insert (symbol_new (regname, reg_section,
RTYPE_VI | i, &zero_address_frag));
/* MSA register. */
- snprintf (regname, sizeof (regname) - 1, "$w%d", i);
+ sprintf (regname, "$w%d", i);
symbol_table_insert (symbol_new (regname, reg_section,
RTYPE_MSA | i, &zero_address_frag));
}
static void
check_fpabi (int fpabi)
{
- bfd_boolean needs_check = FALSE;
switch (fpabi)
{
case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ if (file_mips_opts.soft_float)
+ fpabi_incompatible_with (fpabi, "softfloat");
+ else if (file_mips_opts.single_float)
+ fpabi_incompatible_with (fpabi, "singlefloat");
if (file_mips_opts.gp == 64 && file_mips_opts.fp == 32)
fpabi_incompatible_with (fpabi, "gp=64 fp=32");
else if (file_mips_opts.gp == 32 && file_mips_opts.fp == 64)
fpabi_incompatible_with (fpabi, "gp=32 fp=64");
- else
- needs_check = TRUE;
break;
case Val_GNU_MIPS_ABI_FP_XX:
if (mips_abi != O32_ABI)
fpabi_requires (fpabi, "-mabi=32");
+ else if (file_mips_opts.soft_float)
+ fpabi_incompatible_with (fpabi, "softfloat");
+ else if (file_mips_opts.single_float)
+ fpabi_incompatible_with (fpabi, "singlefloat");
else if (file_mips_opts.fp != 0)
fpabi_requires (fpabi, "fp=xx");
- else
- needs_check = TRUE;
break;
case Val_GNU_MIPS_ABI_FP_64A:
case Val_GNU_MIPS_ABI_FP_64:
if (mips_abi != O32_ABI)
fpabi_requires (fpabi, "-mabi=32");
+ else if (file_mips_opts.soft_float)
+ fpabi_incompatible_with (fpabi, "softfloat");
+ else if (file_mips_opts.single_float)
+ fpabi_incompatible_with (fpabi, "singlefloat");
else if (file_mips_opts.fp != 64)
fpabi_requires (fpabi, "fp=64");
else if (fpabi == Val_GNU_MIPS_ABI_FP_64 && !file_mips_opts.oddspreg)
fpabi_incompatible_with (fpabi, "nooddspreg");
else if (fpabi == Val_GNU_MIPS_ABI_FP_64A && file_mips_opts.oddspreg)
fpabi_requires (fpabi, "nooddspreg");
- else
- needs_check = TRUE;
break;
case Val_GNU_MIPS_ABI_FP_SINGLE:
Tag_GNU_MIPS_ABI_FP, fpabi);
break;
+ case Val_GNU_MIPS_ABI_FP_NAN2008:
+ /* Silently ignore compatibility value. */
+ break;
+
default:
as_warn (_(".gnu_attribute %d,%d is not a recognized"
" floating-point ABI"), Tag_GNU_MIPS_ABI_FP, fpabi);
break;
}
-
- if (needs_check && file_mips_opts.soft_float)
- fpabi_incompatible_with (fpabi, "softfloat");
- else if (needs_check && file_mips_opts.single_float)
- fpabi_incompatible_with (fpabi, "singlefloat");
}
/* Perform consistency checks on the current options. */
if (abi_checks
&& ABI_NEEDS_64BIT_REGS (mips_abi))
as_warn (_("`fp=32' used with a 64-bit ABI"));
+ if (ISA_IS_R6 (opts->isa) && opts->single_float == 0)
+ as_bad (_("`fp=32' used with a MIPS R6 cpu"));
break;
default:
as_bad (_("Unknown size of floating point registers"));
as_bad (_("`nooddspreg` cannot be used with a 64-bit ABI"));
if (opts->micromips == 1 && opts->mips16 == 1)
- as_bad (_("`mips16' cannot be used with `micromips'"));
+ as_bad (_("`%s' cannot be used with `%s'"), "mips16", "micromips");
+ else if (ISA_IS_R6 (opts->isa)
+ && (opts->micromips == 1
+ || opts->mips16 == 1))
+ as_fatal (_("`%s' cannot be used with `%s'"),
+ opts->micromips ? "micromips" : "mips16",
+ mips_cpu_info_from_isa (opts->isa)->name);
+
+ if (ISA_IS_R6 (opts->isa) && mips_relax_branch)
+ as_fatal (_("branch relaxation is not supported in `%s'"),
+ mips_cpu_info_from_isa (opts->isa)->name);
}
/* Perform consistency checks on the module level options exactly once.
&& ISA_HAS_64BIT_FPRS (file_mips_opts.isa))
/* Handle ASEs that require 64-bit float registers, if possible. */
file_mips_opts.fp = 64;
+ else if (ISA_IS_R6 (mips_opts.isa))
+ /* R6 implies 64-bit float registers. */
+ file_mips_opts.fp = 64;
else
/* 32-bit float registers. */
file_mips_opts.fp = 32;
file_mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
? 1 : 0;
+ if (mips_nan2008 == -1)
+ mips_nan2008 = (ISA_HAS_LEGACY_NAN (file_mips_opts.isa)) ? 0 : 1;
+ else if (!ISA_HAS_LEGACY_NAN (file_mips_opts.isa) && mips_nan2008 == 0)
+ as_fatal (_("`%s' does not support legacy NaN"),
+ mips_cpu_info_from_arch (file_mips_opts.arch)->name);
+
/* Some ASEs require 64-bit FPRs, so -mfp32 should stop those ASEs from
being selected implicitly. */
if (file_mips_opts.fp != 64)
case BFD_RELOC_MICROMIPS_7_PCREL_S1:
case BFD_RELOC_MICROMIPS_10_PCREL_S1:
case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+ case BFD_RELOC_MIPS_21_PCREL_S2:
+ case BFD_RELOC_MIPS_26_PCREL_S2:
+ case BFD_RELOC_MIPS_18_PCREL_S3:
+ case BFD_RELOC_MIPS_19_PCREL_S2:
return TRUE;
case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_HI16_S_PCREL:
+ case BFD_RELOC_LO16_PCREL:
return HAVE_64BIT_ADDRESSES;
default:
uval = insn_extract_operand (insn, operand);
return (1 << (uval & 31)) | (1 << (uval >> 5));
+ case OP_SAME_RS_RT:
+ if (!(type_mask & (1 << OP_REG_GP)))
+ return 0;
+ uval = insn_extract_operand (insn, operand);
+ gas_assert ((uval & 31) == (uval >> 5));
+ return 1 << (uval & 31);
+
+ case OP_CHECK_PREV:
+ case OP_NON_ZERO_REG:
+ if (!(type_mask & (1 << OP_REG_GP)))
+ return 0;
+ uval = insn_extract_operand (insn, operand);
+ return 1 << (uval & 31);
+
case OP_LWM_SWM_LIST:
abort ();
return TRUE;
}
+/* OP_CHECK_PREV matcher. */
+
+static bfd_boolean
+match_check_prev_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand_base)
+{
+ const struct mips_check_prev_operand *operand;
+ unsigned int regno;
+
+ operand = (const struct mips_check_prev_operand *) operand_base;
+
+ if (!match_reg (arg, OP_REG_GP, ®no))
+ return FALSE;
+
+ if (!operand->zero_ok && regno == 0)
+ return FALSE;
+
+ if ((operand->less_than_ok && regno < arg->last_regno)
+ || (operand->greater_than_ok && regno > arg->last_regno)
+ || (operand->equal_ok && regno == arg->last_regno))
+ {
+ arg->last_regno = regno;
+ insn_insert_operand (arg->insn, operand_base, regno);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* OP_SAME_RS_RT matcher. */
+
+static bfd_boolean
+match_same_rs_rt_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int regno;
+
+ if (!match_reg (arg, OP_REG_GP, ®no))
+ return FALSE;
+
+ if (regno == 0)
+ {
+ 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 | (regno << 5));
+ return TRUE;
+}
+
/* OP_LWM_SWM_LIST matcher. */
static bfd_boolean
return FALSE;
}
+/* OP_NON_ZERO_REG matcher. */
+
+static bfd_boolean
+match_non_zero_reg_operand (struct mips_arg_info *arg,
+ const struct mips_operand *operand)
+{
+ unsigned int regno;
+
+ if (!match_reg (arg, OP_REG_GP, ®no))
+ return FALSE;
+
+ if (regno == 0)
+ return FALSE;
+
+ arg->last_regno = regno;
+ insn_insert_operand (arg->insn, operand, regno);
+ return TRUE;
+}
+
/* OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG matcher. OTHER_REGNO is the
register that we need to match. */
case OP_REG_INDEX:
return match_reg_index_operand (arg, operand);
+
+ case OP_SAME_RS_RT:
+ return match_same_rs_rt_operand (arg, operand);
+
+ case OP_CHECK_PREV:
+ return match_check_prev_operand (arg, operand);
+
+ case OP_NON_ZERO_REG:
+ return match_non_zero_reg_operand (arg, operand);
}
abort ();
}
return 1;
}
+ /* Forbidden slots can not contain Control Transfer Instructions (CTIs)
+ CTIs include all branches and jumps, nal, eret, eretnc, deret, wait
+ and pause. */
+ if ((insn1->insn_mo->pinfo2 & INSN2_FORBIDDEN_SLOT)
+ && ((pinfo2 & INSN_NO_DELAY_SLOT)
+ || (insn2 && delayed_branch_p (insn2))))
+ return 1;
+
return 0;
}
return 0;
}
-#define BASE_REG_EQ(INSN1, INSN2) \
- ((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
+#define BASE_REG_EQ(INSN1, INSN2) \
+ ((((INSN1) >> OP_SH_RS) & OP_MASK_RS) \
== (((INSN2) >> OP_SH_RS) & OP_MASK_RS))
/* Return the minimum alignment for this store instruction. */
* Run the data cache in write-through mode.
* Insert a non-store instruction between
Store A and Store B or Store B and Store C. */
-
+
static int
nops_for_24k (int ignore, const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
/* Parameter must be 16 bit. */
&& (*reloc_type == BFD_RELOC_16_PCREL_S2)
/* Branch to same segment. */
- && (S_GET_SEGMENT(address_expr->X_add_symbol) == now_seg)
+ && (S_GET_SEGMENT (address_expr->X_add_symbol) == now_seg)
/* Branch to same code fragment. */
- && (symbol_get_frag(address_expr->X_add_symbol) == frag_now)
+ && (symbol_get_frag (address_expr->X_add_symbol) == frag_now)
/* Can only calculate branch offset if value is known. */
- && symbol_constant_p(address_expr->X_add_symbol)
+ && symbol_constant_p (address_expr->X_add_symbol)
/* Check if branch is really conditional. */
&& !((ip->insn_opcode & 0xffff0000) == 0x10000000 /* beq $0,$0 */
|| (ip->insn_opcode & 0xffff0000) == 0x04010000 /* bgez $0 */
int distance;
/* Check if loop is shorter than 6 instructions including
branch and delay slot. */
- distance = frag_now_fix() - S_GET_VALUE(address_expr->X_add_symbol);
+ distance = frag_now_fix () - S_GET_VALUE (address_expr->X_add_symbol);
if (distance <= 20)
{
int i;
for (i = 0; i < (distance / 4); i++)
{
if ((history[i].cleared_p)
- || delayed_branch_p(&history[i]))
+ || delayed_branch_p (&history[i]))
{
rv = TRUE;
break;
{
int shift;
- shift = mips_opts.micromips ? 1 : 2;
+ /* Shift is 2, unusually, for microMIPS JALX. */
+ shift = (mips_opts.micromips
+ && strcmp (ip->insn_mo->name, "jalx") != 0) ? 1 : 2;
if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
as_bad (_("jump to misaligned address (0x%lx)"),
(unsigned long) address_expr->X_add_number);
}
break;
+ case BFD_RELOC_MIPS_21_PCREL_S2:
+ {
+ int shift;
+
+ shift = 2;
+ if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+ as_bad (_("branch to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ if ((address_expr->X_add_number + (1 << (shift + 20)))
+ & ~((1 << (shift + 21)) - 1))
+ as_bad (_("branch address range overflow (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+ & 0x1fffff);
+ }
+ break;
+
+ case BFD_RELOC_MIPS_26_PCREL_S2:
+ {
+ int shift;
+
+ shift = 2;
+ if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+ as_bad (_("branch to misaligned address (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ if ((address_expr->X_add_number + (1 << (shift + 25)))
+ & ~((1 << (shift + 26)) - 1))
+ as_bad (_("branch address range overflow (0x%lx)"),
+ (unsigned long) address_expr->X_add_number);
+ ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+ & 0x3ffffff);
+ }
+ break;
+
default:
{
offsetT value;
if (hi_fixup == 0
|| !fixup_has_matching_lo_p (hi_fixup->fixp))
{
- hi_fixup = ((struct mips_hi_fixup *)
- xmalloc (sizeof (struct mips_hi_fixup)));
+ hi_fixup = XNEW (struct mips_hi_fixup);
hi_fixup->next = mips_hi_fixup_list;
mips_hi_fixup_list = hi_fixup;
}
arg.opnum += 1;
switch (*args)
{
+ case '-':
+ switch (args[1])
+ {
+ case 'A':
+ *offset_reloc = BFD_RELOC_MIPS_19_PCREL_S2;
+ break;
+
+ case 'B':
+ *offset_reloc = BFD_RELOC_MIPS_18_PCREL_S3;
+ break;
+ }
+ break;
+
case '+':
switch (args[1])
{
case 'i':
*offset_reloc = BFD_RELOC_MIPS_JMP;
break;
+
+ case '\'':
+ *offset_reloc = BFD_RELOC_MIPS_26_PCREL_S2;
+ break;
+
+ case '\"':
+ *offset_reloc = BFD_RELOC_MIPS_21_PCREL_S2;
+ break;
}
break;
abort ();
/* Skip prefixes. */
- if (*args == '+' || *args == 'm')
+ if (*args == '+' || *args == 'm' || *args == '-')
args++;
if (mips_optional_operand_p (operand)
static const char * const trap_fmt[2] = { "s,t,q", "s,t,|" };
#define BRK_FMT (brk_fmt[mips_opts.micromips][mips_opts.insn32])
-#define COP12_FMT (cop12_fmt[mips_opts.micromips])
+#define COP12_FMT (ISA_IS_R6 (mips_opts.isa) ? "E,+:(d)" \
+ : cop12_fmt[mips_opts.micromips])
#define JALR_FMT (jalr_fmt[mips_opts.micromips])
#define LUI_FMT (lui_fmt[mips_opts.micromips])
#define MEM12_FMT (mem12_fmt[mips_opts.micromips])
+#define LL_SC_FMT (ISA_IS_R6 (mips_opts.isa) ? "t,+j(b)" \
+ : mem12_fmt[mips_opts.micromips])
#define MFHL_FMT (mfhl_fmt[mips_opts.micromips][mips_opts.insn32])
#define SHFT_FMT (shft_fmt[mips_opts.micromips])
#define TRAP_FMT (trap_fmt[mips_opts.micromips])
uval |= (uval << 5);
insn_insert_operand (&insn, operand, uval);
- if (*fmt == '+' || *fmt == 'm')
+ if (*fmt == '+' || *fmt == 'm' || *fmt == '-')
++fmt;
break;
}
&& !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
macro_build (NULL, "move", "mp,mj", dest, source);
else
- macro_build (NULL, GPR_SIZE == 32 ? "addu" : "daddu", "d,v,t",
- dest, source, 0);
+ macro_build (NULL, "or", "d,v,t", dest, source, 0);
}
/* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
breg = op[2];
if (dbl && GPR_SIZE == 32)
- as_warn (_("dla used to load 32-bit register"));
+ as_warn (_("dla used to load 32-bit register; recommend using la "
+ "instead"));
if (!dbl && HAVE_64BIT_OBJECTS)
- as_warn (_("la used to load 64-bit address"));
+ as_warn (_("la used to load 64-bit address; recommend using dla "
+ "instead"));
if (small_offset_p (0, align, 16))
{
if (mips_opts.noreorder)
macro_build (NULL, "nop", "");
expr1.X_add_number = mips_cprestore_offset;
- macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
+ macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
mips_gp_register,
mips_frame_reg,
HAVE_64BIT_ADDRESSES);
if (mips_opts.noreorder)
macro_build (NULL, "nop", "");
expr1.X_add_number = mips_cprestore_offset;
- macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
+ macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
mips_gp_register,
mips_frame_reg,
HAVE_64BIT_ADDRESSES);
case M_LWC2_AB:
s = "lwc2";
fmt = COP12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
case M_LDC2_AB:
s = "ldc2";
fmt = COP12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
goto ld_st;
case M_LL_AB:
s = "ll";
- fmt = MEM12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld;
case M_LLD_AB:
s = "lld";
- fmt = MEM12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld;
case M_LWU_AB:
s = "lwu";
case M_SWC2_AB:
s = "swc2";
fmt = COP12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
goto ld_st;
case M_SC_AB:
s = "sc";
- fmt = MEM12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld_st;
case M_SCD_AB:
s = "scd";
- fmt = MEM12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld_st;
case M_CACHE_AB:
s = "cache";
- fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = (mips_opts.micromips ? "k,~(b)"
+ : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+ : "k,o(b)");
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld_st;
case M_CACHEE_AB:
s = "cachee";
goto ld_st;
case M_PREF_AB:
s = "pref";
- fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
- offbits = (mips_opts.micromips ? 12 : 16);
+ fmt = (mips_opts.micromips ? "k,~(b)"
+ : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+ : "k,o(b)");
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
goto ld_st;
case M_PREFE_AB:
s = "prefe";
case M_SDC2_AB:
s = "sdc2";
fmt = COP12_FMT;
- offbits = (mips_opts.micromips ? 12 : 16);
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
/* Itbl support may require additional care here. */
coproc = 1;
goto ld_st;
&& offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
- {
- op[2] = mips_gp_register;
+ {
+ op[2] = mips_gp_register;
offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
offset_reloc[0] = BFD_RELOC_LO16;
offset_reloc[1] = BFD_RELOC_UNUSED;
offset_reloc[2] = BFD_RELOC_UNUSED;
- }
+ }
align = 8;
/* Fall through */
abort ();
break;
-
+
case M_SAA_AB:
s = "saa";
goto saa_saad;
case M_DROL_I:
{
unsigned int rot;
- char *l;
- char *rr;
+ const char *l;
+ const char *rr;
rot = imm_expr.X_add_number & 0x3f;
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
case M_DROR_I:
{
unsigned int rot;
- char *l;
- char *rr;
+ const char *l;
+ const char *rr;
rot = imm_expr.X_add_number & 0x3f;
if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
struct mips_opcode *insn;
/* Make a copy of the instruction so that we can fiddle with it. */
- name = alloca (length + 1);
- memcpy (name, start, length);
- name[length] = '\0';
+ name = xstrndup (start, length);
/* Look up the instruction as-is. */
insn = (struct mips_opcode *) hash_find (hash, name);
if (insn)
- return insn;
+ goto end;
dot = strchr (name, '.');
if (dot && dot[1])
if (insn && (insn->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) != 0)
{
*opcode_extra |= mask << mips_vu0_channel_mask.lsb;
- return insn;
+ goto end;
}
}
}
if (insn)
{
forced_insn_length = suffix;
- return insn;
+ goto end;
}
}
}
- return NULL;
+ insn = NULL;
+ end:
+ free (name);
+ return insn;
}
/* Assemble an instruction into its binary format. If the instruction
is the length that the user requested, or 0 if none. */
static void
-mips16_immed (char *file, unsigned int line, int type,
+mips16_immed (const char *file, unsigned int line, int type,
bfd_reloc_code_real_type reloc, offsetT val,
unsigned int user_insn_length, unsigned long *insn)
{
{"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16},
{"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16},
{"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
- {"%hi", BFD_RELOC_HI16_S}
+ {"%hi", BFD_RELOC_HI16_S},
+ {"%pcrel_hi", BFD_RELOC_HI16_S_PCREL},
+ {"%pcrel_lo", BFD_RELOC_LO16_PCREL}
};
static const struct percent_op_match mips16_percent_op[] =
input_line_pointer = save_in;
}
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
unsigned int i;
file_mips_opts.isa = ISA_MIPS32R5;
break;
+ case OPTION_MIPS32R6:
+ file_mips_opts.isa = ISA_MIPS32R6;
+ break;
+
case OPTION_MIPS64R2:
file_mips_opts.isa = ISA_MIPS64R2;
break;
file_mips_opts.isa = ISA_MIPS64R5;
break;
+ case OPTION_MIPS64R6:
+ file_mips_opts.isa = ISA_MIPS64R6;
+ break;
+
case OPTION_MIPS64:
file_mips_opts.isa = ISA_MIPS64;
break;
case OPTION_NAN:
if (strcmp (arg, "2008") == 0)
- mips_flag_nan2008 = TRUE;
+ mips_nan2008 = 1;
else if (strcmp (arg, "legacy") == 0)
- mips_flag_nan2008 = FALSE;
+ mips_nan2008 = 0;
else
{
as_fatal (_("invalid NaN setting -mnan=%s"), arg);
case BFD_RELOC_MICROMIPS_16_PCREL_S1:
case BFD_RELOC_MICROMIPS_JMP:
case BFD_RELOC_16_PCREL_S2:
+ case BFD_RELOC_MIPS_21_PCREL_S2:
+ case BFD_RELOC_MIPS_26_PCREL_S2:
case BFD_RELOC_MIPS_JMP:
/* Return the address of the delay slot. */
return addr + 4;
|| fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
return 1;
+ /* We want all PC-relative relocations to be kept for R6 relaxation. */
+ if (ISA_IS_R6 (mips_opts.isa)
+ && (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MIPS_21_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
+ || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+ || fixp->fx_r_type == BFD_RELOC_LO16_PCREL))
+ return 1;
+
return 0;
}
case BFD_RELOC_MICROMIPS_10_PCREL_S1:
case BFD_RELOC_MICROMIPS_16_PCREL_S1:
case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_MIPS_21_PCREL_S2:
+ case BFD_RELOC_MIPS_26_PCREL_S2:
+ case BFD_RELOC_MIPS_18_PCREL_S3:
+ case BFD_RELOC_MIPS_19_PCREL_S2:
+ case BFD_RELOC_HI16_S_PCREL:
+ case BFD_RELOC_LO16_PCREL:
break;
case BFD_RELOC_32:
|| fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
+ || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64
+ || fixP->fx_r_type == BFD_RELOC_NONE);
buf = fixP->fx_frag->fr_literal + fixP->fx_where;
md_number_to_chars (buf, *valP, fixP->fx_size);
break;
+ case BFD_RELOC_MIPS_21_PCREL_S2:
+ case BFD_RELOC_MIPS_26_PCREL_S2:
+ if ((*valP & 0x3) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("branch to misaligned address (%lx)"), (long) *valP);
+
+ gas_assert (!fixP->fx_done);
+ break;
+
+ case BFD_RELOC_MIPS_18_PCREL_S3:
+ if ((S_GET_VALUE (fixP->fx_addsy) & 0x7) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC-relative access using misaligned symbol (%lx)"),
+ (long) S_GET_VALUE (fixP->fx_addsy));
+ if ((fixP->fx_offset & 0x7) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC-relative access using misaligned offset (%lx)"),
+ (long) fixP->fx_offset);
+
+ gas_assert (!fixP->fx_done);
+ break;
+
+ case BFD_RELOC_MIPS_19_PCREL_S2:
+ if ((*valP & 0x3) != 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC-relative access to misaligned address (%lx)"),
+ (long) (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset));
+
+ gas_assert (!fixP->fx_done);
+ break;
+
+ case BFD_RELOC_HI16_S_PCREL:
+ case BFD_RELOC_LO16_PCREL:
+ gas_assert (!fixP->fx_done);
+ break;
+
case BFD_RELOC_16_PCREL_S2:
if ((*valP & 0x3) != 0)
as_bad_where (fixP->fx_file, fixP->fx_line,
S_SET_WEAK (fixP->fx_addsy);
break;
+ case BFD_RELOC_NONE:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = 0;
break;
char *name;
symbolS *p;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
p = (symbolS *) symbol_find_or_make (name);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
return p;
}
void
s_change_section (int ignore ATTRIBUTE_UNUSED)
{
+ char *saved_ilp;
char *section_name;
- char c;
+ char c, endc;
char next_c = 0;
int section_type;
int section_flag;
int section_entry_size;
int section_alignment;
- section_name = input_line_pointer;
- c = get_symbol_end ();
+ saved_ilp = input_line_pointer;
+ endc = get_symbol_name (§ion_name);
+ c = (endc == '"' ? input_line_pointer[1] : endc);
if (c)
- next_c = *(input_line_pointer + 1);
+ next_c = input_line_pointer [(endc == '"' ? 2 : 1)];
/* Do we have .section Name<,"flags">? */
if (c != ',' || (c == ',' && next_c == '"'))
{
- /* just after name is now '\0'. */
- *input_line_pointer = c;
- input_line_pointer = section_name;
+ /* Just after name is now '\0'. */
+ (void) restore_line_pointer (endc);
+ input_line_pointer = saved_ilp;
obj_elf_section (ignore);
return;
}
+
+ section_name = xstrdup (section_name);
+ c = restore_line_pointer (endc);
+
input_line_pointer++;
/* Do we have .section Name<,type><,flag><,entry_size><,alignment> */
section_type = get_absolute_expression ();
else
section_type = 0;
+
if (*input_line_pointer++ == ',')
section_flag = get_absolute_expression ();
else
section_flag = 0;
+
if (*input_line_pointer++ == ',')
section_entry_size = get_absolute_expression ();
else
section_entry_size = 0;
+
if (*input_line_pointer++ == ',')
section_alignment = get_absolute_expression ();
else
section_alignment = 0;
+
/* FIXME: really ignore? */
(void) section_alignment;
- section_name = xstrdup (section_name);
-
/* When using the generic form of .section (as implemented by obj-elf.c),
there's no way to set the section type to SHT_MIPS_DWARF. Users have
traditionally had to fall back on the more common @progbits instead.
do
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
symbolP = symbol_find_or_make (name);
S_SET_EXTERNAL (symbolP);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ 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. */
char *secname;
asection *sec;
- secname = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&secname);
sec = bfd_get_section_by_name (stdoutput, secname);
if (sec == NULL)
as_bad (_("%s: no such section"), secname);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
if (sec != NULL && (sec->flags & SEC_CODE) != 0)
flag = BSF_FUNCTION;
char *opt;
char c;
- opt = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&opt);
if (*opt == 'O')
{
/* FIXME: What does this mean? */
}
- else if (strncmp (opt, "pic", 3) == 0)
+ else if (strncmp (opt, "pic", 3) == 0 && ISDIGIT (opt[3]) && opt[4] == '\0')
{
int i;
i = atoi (opt + 3);
- if (i == 0)
+ if (i != 0 && i != 2)
+ as_bad (_(".option pic%d not supported"), i);
+ else if (mips_pic == VXWORKS_PIC)
+ as_bad (_(".option pic%d not supported in VxWorks PIC mode"), i);
+ else if (i == 0)
mips_pic = NO_PIC;
else if (i == 2)
{
mips_pic = SVR4_PIC;
mips_abicalls = TRUE;
}
- else
- as_bad (_(".option pic%d not supported"), i);
if (mips_pic == SVR4_PIC)
{
else
as_warn (_("unrecognized option \"%s\""), opt);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
demand_empty_rest_of_line ();
}
static struct mips_option_stack *mips_opts_stack;
-static bfd_boolean
+/* Return status for .set/.module option handling. */
+
+enum code_option_type
+{
+ /* Unrecognized option. */
+ OPTION_TYPE_BAD = -1,
+
+ /* Ordinary option. */
+ OPTION_TYPE_NORMAL,
+
+ /* ISA changing option. */
+ OPTION_TYPE_ISA
+};
+
+/* Handle common .set/.module options. Return status indicating option
+ type. */
+
+static enum code_option_type
parse_code_option (char * name)
{
+ bfd_boolean isa_set = FALSE;
const struct mips_ase *ase;
+
if (strncmp (name, "at=", 3) == 0)
{
char *s = name + 3;
{
mips_opts.arch = p->cpu;
mips_opts.isa = p->isa;
+ isa_set = TRUE;
}
}
else if (strncmp (name, "mips", 4) == 0)
{
mips_opts.arch = p->cpu;
mips_opts.isa = p->isa;
+ isa_set = TRUE;
}
}
else
else if (strcmp (name, "nosym32") == 0)
mips_opts.sym32 = FALSE;
else
- return FALSE;
- return TRUE;
+ return OPTION_TYPE_BAD;
+
+ return isa_set ? OPTION_TYPE_ISA : OPTION_TYPE_NORMAL;
}
/* Handle the .set pseudo-op. */
static void
s_mipsset (int x ATTRIBUTE_UNUSED)
{
+ enum code_option_type type = OPTION_TYPE_NORMAL;
char *name = input_line_pointer, ch;
- int prev_isa = mips_opts.isa;
file_mips_check_options ();
{
struct mips_option_stack *s;
- s = (struct mips_option_stack *) xmalloc (sizeof *s);
+ s = XNEW (struct mips_option_stack);
s->next = mips_opts_stack;
s->options = mips_opts;
mips_opts_stack = s;
free (s);
}
}
- else if (!parse_code_option (name))
- as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+ else
+ {
+ type = parse_code_option (name);
+ if (type == OPTION_TYPE_BAD)
+ as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+ }
/* The use of .set [arch|cpu]= historically 'fixes' the width of gp and fp
registers based on what is supported by the arch/cpu. */
- if (mips_opts.isa != prev_isa)
+ if (type == OPTION_TYPE_ISA)
{
switch (mips_opts.isa)
{
if (mips_opts.fp != 0)
mips_opts.fp = 32;
break;
+ case ISA_MIPS32R6:
+ mips_opts.gp = 32;
+ mips_opts.fp = 64;
+ break;
case ISA_MIPS3:
case ISA_MIPS4:
case ISA_MIPS5:
case ISA_MIPS64R2:
case ISA_MIPS64R3:
case ISA_MIPS64R5:
+ case ISA_MIPS64R6:
mips_opts.gp = 64;
if (mips_opts.fp != 0)
{
if (!file_mips_opts_checked)
{
- if (!parse_code_option (name))
+ if (parse_code_option (name) == OPTION_TYPE_BAD)
as_bad (_(".module used with unrecognized symbol: %s\n"), name);
/* Update module level settings from mips_opts. */
daddu $gp, $gp, $reg1
If $reg2 is given, this results in:
- daddu $reg2, $gp, $0
+ or $reg2, $gp, $0
lui $gp, %hi(%neg(%gp_rel(label)))
addiu $gp, $gp, %lo(%neg(%gp_rel(label)))
daddu $gp, $gp, $reg1
BFD_RELOC_LO16, SP);
}
else
- macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register,
- mips_gp_register, 0);
+ move_register (mips_cpreturn_register, mips_gp_register);
if (mips_in_shared || HAVE_64BIT_SYMBOLS)
{
ld $gp, offset($sp)
If a register $reg2 was given there, it results in:
- daddu $gp, $reg2, $0 */
+ or $gp, $reg2, $0 */
static void
s_cpreturn (int ignore ATTRIBUTE_UNUSED)
macro_build (&ex, "ld", "t,o(b)", mips_gp_register, BFD_RELOC_LO16, SP);
}
else
- macro_build (NULL, "daddu", "d,v,t", mips_gp_register,
- mips_cpreturn_register, 0);
+ move_register (mips_gp_register, mips_cpreturn_register);
+
macro_end ();
mips_assembling_insn = FALSE;
p = frag_more (4);
md_number_to_chars (p, 0, 4);
fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
- BFD_RELOC_MIPS_EH);
+ BFD_RELOC_32_PCREL);
demand_empty_rest_of_line ();
}
static void
s_insn (int ignore ATTRIBUTE_UNUSED)
{
+ file_mips_check_options ();
+ file_ase_mips16 |= mips_opts.mips16;
+ file_ase_micromips |= mips_opts.micromips;
+
mips_mark_labels ();
demand_empty_rest_of_line ();
if (i == sizeof (str_2008) - 1
&& memcmp (input_line_pointer, str_2008, i) == 0)
- mips_flag_nan2008 = TRUE;
+ mips_nan2008 = 1;
else if (i == sizeof (str_legacy) - 1
&& memcmp (input_line_pointer, str_legacy, i) == 0)
- mips_flag_nan2008 = FALSE;
+ {
+ if (ISA_HAS_LEGACY_NAN (file_mips_opts.isa))
+ mips_nan2008 = 0;
+ else
+ as_bad (_("`%s' does not support legacy NaN"),
+ mips_cpu_info_from_isa (file_mips_opts.isa)->name);
+ }
else
as_bad (_("bad .nan directive"));
directive, such as in:
foo:
- .stabs ...
+ .stabs ...
.set mips16
so the current mode wins. */
symbolS *symbolP;
expressionS exp;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
symbolP = symbol_find_or_make (name);
S_SET_WEAK (symbolP);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (! is_end_of_line[(unsigned char) *input_line_pointer])
{
if (align > 4)
align = 4;
- return ((addr + (1 << align) - 1) & (-1 << align));
+ return ((addr + (1 << align) - 1) & -(1 << align));
}
/* Utility routine, called from above as well. If called while the
if (fragp
&& S_IS_DEFINED (fragp->fr_symbol)
+ && !S_IS_WEAK (fragp->fr_symbol)
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
addressT addr;
toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
}
- else if (fragp)
- /* If the symbol is not defined or it's in a different segment,
- assume the user knows what's going on and emit a short
- branch. */
- toofar = FALSE;
else
+ /* If the symbol is not defined or it's in a different segment,
+ we emit the long sequence. */
toofar = TRUE;
if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
if (fragp
&& S_IS_DEFINED (fragp->fr_symbol)
+ && !S_IS_WEAK (fragp->fr_symbol)
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
addressT addr;
toofar = val < - (0x8000 << 1) || val >= (0x8000 << 1);
}
- else if (fragp)
- /* If the symbol is not defined or it's in a different segment,
- assume the user knows what's going on and emit a short
- branch. */
- toofar = FALSE;
else
+ /* If the symbol is not defined or it's in a different segment,
+ we emit the long sequence. */
toofar = TRUE;
if (fragp && update
if (fragp
&& S_IS_DEFINED (fragp->fr_symbol)
+ && !S_IS_WEAK (fragp->fr_symbol)
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
{
addressT addr;
if (fixp->fx_addsy == NULL)
return 1;
+ /* Allow relocs used for EH tables. */
+ if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
+ return 1;
+
/* If symbol SYM is in a mergeable section, relocations of the form
SYM + 0 can usually be made section-relative. The mergeable data
is then identified by the section offset rather than by the symbol.
/* There is no place to store an in-place offset for JALR relocations.
Likewise an in-range offset of limited PC-relative relocations may
overflow the in-place relocatable field if recalculated against the
- start address of the symbol's containing section. */
- if (HAVE_IN_PLACE_ADDENDS
+ start address of the symbol's containing section.
+
+ Also, PC relative relocations for MIPS R6 need to be symbol rather than
+ section relative to allow linker relaxations to be performed later on. */
+ if ((HAVE_IN_PLACE_ADDENDS || ISA_IS_R6 (mips_opts.isa))
&& (limited_pcrel_reloc_p (fixp->fx_r_type)
|| jalr_reloc_p (fixp->fx_r_type)))
return 0;
bfd_reloc_code_real_type code;
memset (retval, 0, sizeof(retval));
- reloc = retval[0] = (arelent *) xcalloc (1, sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc = retval[0] = XCNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
|| fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
|| fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
|| fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
- || fixp->fx_r_type == BFD_RELOC_32_PCREL);
+ || fixp->fx_r_type == BFD_RELOC_32_PCREL
+ || fixp->fx_r_type == BFD_RELOC_MIPS_21_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
+ || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+ || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+ || fixp->fx_r_type == BFD_RELOC_LO16_PCREL);
/* At this point, fx_addnumber is "symbol offset - pcrel address".
Relocations want only the symbol offset. */
reloc->addend = fixp->fx_addnumber + reloc->address;
}
+ else if (HAVE_IN_PLACE_ADDENDS
+ && fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP
+ && (read_compressed_insn (fixp->fx_frag->fr_literal
+ + fixp->fx_where, 4) >> 26) == 0x3c)
+ {
+ /* Shift is 2, unusually, for microMIPS JALX. Adjust the in-place
+ addend accordingly. */
+ reloc->addend = fixp->fx_addnumber >> 1;
+ }
else
reloc->addend = fixp->fx_addnumber;
struct insn_label_list *l;
if (free_insn_labels == NULL)
- l = (struct insn_label_list *) xmalloc (sizeof *l);
+ l = XNEW (struct insn_label_list);
else
{
l = free_insn_labels;
ext_ases |= AFL_ASE_DSP;
if (ase & ASE_DSPR2)
ext_ases |= AFL_ASE_DSPR2;
+ if (ase & ASE_DSPR3)
+ ext_ases |= AFL_ASE_DSPR3;
if (ase & ASE_EVA)
ext_ases |= AFL_ASE_EVA;
if (ase & ASE_MCU)
flags.isa_level = 32;
flags.isa_rev = 5;
break;
+ case INSN_ISA32R6:
+ flags.isa_level = 32;
+ flags.isa_rev = 6;
+ break;
case INSN_ISA64:
flags.isa_level = 64;
flags.isa_rev = 1;
flags.isa_level = 64;
flags.isa_rev = 5;
break;
+ case INSN_ISA64R6:
+ flags.isa_level = 64;
+ flags.isa_rev = 6;
+ break;
}
flags.gpr_size = file_mips_opts.gp == 32 ? AFL_REG_32 : AFL_REG_64;
if (mips_32bitmode)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
- if (mips_flag_nan2008)
+ if (mips_nan2008 == 1)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
/* 32 bit code with 64 bit FP registers. */
if (p && cur_proc_ptr)
{
OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (p);
- expressionS *exp = xmalloc (sizeof (expressionS));
+ expressionS *exp = XNEW (expressionS);
obj->size = exp;
exp->X_op = O_subtract;
{ "mips32r2", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "mips32r3", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R3, CPU_MIPS32R3 },
{ "mips32r5", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R5, CPU_MIPS32R5 },
+ { "mips32r6", MIPS_CPU_IS_ISA, 0, ISA_MIPS32R6, CPU_MIPS32R6 },
{ "mips64", MIPS_CPU_IS_ISA, 0, ISA_MIPS64, CPU_MIPS64 },
{ "mips64r2", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R2, CPU_MIPS64R2 },
{ "mips64r3", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R3, CPU_MIPS64R3 },
{ "mips64r5", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R5, CPU_MIPS64R5 },
+ { "mips64r6", MIPS_CPU_IS_ISA, 0, ISA_MIPS64R6, CPU_MIPS64R6 },
/* MIPS I */
{ "r3000", 0, 0, ISA_MIPS1, CPU_R3000 },
{ "1004kf2_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "1004kf", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
{ "1004kf1_1", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* interaptiv is the new name for 1004kf */
+ { "interaptiv", 0, ASE_DSP | ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 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. */
- { "p5600", 0, ASE_VIRT | ASE_EVA | ASE_XPA, ISA_MIPS32R5, CPU_MIPS32R5 },
+ { "p5600", 0, ASE_VIRT | ASE_EVA | ASE_XPA, ISA_MIPS32R5, CPU_MIPS32R5 },
/* MIPS 64 */
{ "5kc", 0, 0, ISA_MIPS64, CPU_MIPS64 },
{ "sb1", 0, ASE_MIPS3D | ASE_MDMX, ISA_MIPS64, CPU_SB1 },
/* 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 */
{ "octeon", 0, 0, ISA_MIPS64R2, CPU_OCTEON },
{ "octeon+", 0, 0, ISA_MIPS64R2, CPU_OCTEONP },
{ "octeon2", 0, 0, ISA_MIPS64R2, CPU_OCTEON2 },
+ { "octeon3", 0, ASE_VIRT | ASE_VIRT64, ISA_MIPS64R5, CPU_OCTEON3 },
/* RMI Xlr */
{ "xlr", 0, 0, ISA_MIPS64, CPU_XLR },
MIPS64R2 rather than MIPS64. */
{ "xlp", 0, 0, ISA_MIPS64R2, CPU_XLR },
+ /* MIPS 64 Release 6 */
+ { "i6400", 0, ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
+ { "p6600", 0, ASE_VIRT | ASE_MSA, ISA_MIPS64R6, CPU_MIPS64R6},
+
/* End marker */
{ NULL, 0, 0, 0, 0 }
};
-mips32r2 generate MIPS32 release 2 ISA instructions\n\
-mips32r3 generate MIPS32 release 3 ISA instructions\n\
-mips32r5 generate MIPS32 release 5 ISA instructions\n\
+-mips32r6 generate MIPS32 release 6 ISA instructions\n\
-mips64 generate MIPS64 ISA instructions\n\
-mips64r2 generate MIPS64 release 2 ISA instructions\n\
-mips64r3 generate MIPS64 release 3 ISA instructions\n\
-mips64r5 generate MIPS64 release 5 ISA instructions\n\
+-mips64r6 generate MIPS64 release 6 ISA instructions\n\
-march=CPU/-mtune=CPU generate code/schedule for CPU, where CPU is one of:\n"));
first = 1;
-mno-micromips do not generate microMIPS instructions\n"));
fprintf (stream, _("\
-msmartmips generate smartmips instructions\n\
--mno-smartmips do not generate smartmips instructions\n"));
+-mno-smartmips do not generate smartmips instructions\n"));
fprintf (stream, _("\
-mdsp generate DSP instructions\n\
-mno-dsp do not generate DSP instructions\n"));
-mdspr2 generate DSP R2 instructions\n\
-mno-dspr2 do not generate DSP R2 instructions\n"));
fprintf (stream, _("\
+-mdspr3 generate DSP R3 instructions\n\
+-mno-dspr3 do not generate DSP R3 instructions\n"));
+ fprintf (stream, _("\
-mmt generate MT instructions\n\
-mno-mt do not generate MT instructions\n"));
fprintf (stream, _("\
Tag_GNU_MIPS_ABI_FP, fpabi);
}
}
+
+/* Returns the relocation type required for a particular CFI encoding. */
+
+bfd_reloc_code_real_type
+mips_cfi_reloc_for_encoding (int encoding)
+{
+ if (encoding == (DW_EH_PE_sdata4 | DW_EH_PE_pcrel))
+ return BFD_RELOC_32_PCREL;
+ else return BFD_RELOC_NONE;
+}