/* Likewise 64-bit registers. */
#define ABI_NEEDS_64BIT_REGS(ABI) \
- ((ABI) == N32_ABI \
+ ((ABI) == N32_ABI \
|| (ABI) == N64_ABI \
|| (ABI) == O64_ABI)
/* Branch without likely bit. If label is out of range, we turn:
- beq reg1, reg2, label
+ beq reg1, reg2, label
delay slot
into
OPTION_NO_SMARTMIPS,
OPTION_DSPR2,
OPTION_NO_DSPR2,
+ OPTION_DSPR3,
+ OPTION_NO_DSPR3,
OPTION_EVA,
OPTION_NO_EVA,
OPTION_XPA,
{"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},
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,
/* 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 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;
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));
}
if (abi_checks
&& ABI_NEEDS_64BIT_REGS (mips_abi))
as_warn (_("`fp=32' used with a 64-bit ABI"));
- if (ISA_IS_R6 (mips_opts.isa) && opts->single_float == 0)
+ if (ISA_IS_R6 (opts->isa) && opts->single_float == 0)
as_bad (_("`fp=32' used with a MIPS R6 cpu"));
break;
default:
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'"));
- else if (ISA_IS_R6 (mips_opts.isa)
+ 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' can not be used with `%s'"),
+ as_fatal (_("`%s' cannot be used with `%s'"),
opts->micromips ? "micromips" : "mips16",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ 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'"),
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. */
/* 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);
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;
}
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);
&& 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 */
struct mips_opcode *insn;
/* Make a copy of the instruction so that we can fiddle with it. */
- name = xmalloc (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);
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;
case BFD_RELOC_MIPS16_TLS_GOTTPREL:
case BFD_RELOC_MIPS16_TLS_TPREL_HI16:
case BFD_RELOC_MIPS16_TLS_TPREL_LO16:
- if (!fixP->fx_addsy)
- {
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("TLS relocation against a constant"));
- break;
- }
- S_SET_THREAD_LOCAL (fixP->fx_addsy);
- /* fall through */
+ if (fixP->fx_addsy)
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ else
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("TLS relocation against a constant"));
+ break;
case BFD_RELOC_MIPS_JMP:
case BFD_RELOC_MIPS_SHIFT5:
{
/* 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)
{
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 (!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. */
directive, such as in:
foo:
- .stabs ...
+ .stabs ...
.set mips16
so the current mode wins. */
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;
&& (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
return 0;
- /* There is no place to store an in-place offset for JALR relocations.
- Likewise an in-range offset of limited PC-relative relocations may
+ /* There is no place to store an in-place offset for JALR relocations. */
+ if (jalr_reloc_p (fixp->fx_r_type) && HAVE_IN_PLACE_ADDENDS)
+ return 0;
+
+ /* 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.
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)))
+ if (limited_pcrel_reloc_p (fixp->fx_r_type)
+ && (HAVE_IN_PLACE_ADDENDS || ISA_IS_R6 (mips_opts.isa)))
return 0;
/* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
There is a further restriction:
5. We cannot reduce jump relocations (R_MIPS_26, R_MIPS16_26 or
- R_MICROMIPS_26_S1) against MIPS16 or microMIPS symbols on
- targets with in-place addends; the relocation field cannot
- encode the low bit.
+ R_MICROMIPS_26_S1) against MIPS16 or microMIPS symbols because
+ we need to keep the MIPS16 or microMIPS symbol for the purpose
+ of converting JAL to JALX instructions in the linker.
For simplicity, we deal with (3)-(4) by not reducing _any_ relocation
against a MIPS16 symbol. We deal with (5) by by not reducing any
that we have for MIPS16 symbols. */
if (fixp->fx_subsy == NULL
&& (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
- || *symbol_get_tc (fixp->fx_addsy)
- || (HAVE_IN_PLACE_ADDENDS
- && ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
- && jmp_reloc_p (fixp->fx_r_type))))
+ || (ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
+ && jmp_reloc_p (fixp->fx_r_type))
+ || *symbol_get_tc (fixp->fx_addsy)))
return 0;
return 1;
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;
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)
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;
{ "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 },
MIPS64R2 rather than MIPS64. */
{ "xlp", 0, 0, ISA_MIPS64R2, CPU_XLR },
- /* i6400. */
+ /* 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 }
-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, _("\