/* tc-mips.c -- assemble code for a MIPS chip.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 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
int arch;
/* True if ".set sym32" is in effect. */
bfd_boolean sym32;
+ /* True if floating-point operations are not allowed. Changed by .set
+ softfloat or .set hardfloat, by command line options -msoft-float or
+ -mhard-float. The default is false. */
+ bfd_boolean soft_float;
+
+ /* True if only single-precision floating-point operations are allowed.
+ Changed by .set singlefloat or .set doublefloat, command-line options
+ -msingle-float or -mdouble-float. The default is false. */
+ bfd_boolean single_float;
};
+/* This is the struct we use to hold the current set of options. Note
+ that we must set the isa field to ISA_UNKNOWN and the ASE fields to
+ -1 to indicate that they have not been initialized. */
+
/* True if -mgp32 was passed. */
static int file_mips_gp32 = -1;
/* True if -mfp32 was passed. */
static int file_mips_fp32 = -1;
-/* This is the struct we use to hold the current set of options. Note
- that we must set the isa field to ISA_UNKNOWN and the ASE fields to
- -1 to indicate that they have not been initialized. */
+/* 1 if -msoft-float, 0 if -mhard-float. The default is 0. */
+static int file_mips_soft_float = 0;
+
+/* 1 if -msingle-float, 0 if -mdouble-float. The default is 0. */
+static int file_mips_single_float = 0;
static struct mips_set_options mips_opts =
{
- ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, -1, 0, ATREG, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
+ /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
+ /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
+ /* mips16 */ -1, /* noreorder */ 0, /* at */ ATREG,
+ /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
+ /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
+ /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
};
/* These variables are filled in with the masks of registers used.
|| mips_opts.isa == ISA_MIPS64 \
|| mips_opts.isa == ISA_MIPS64R2)
+/* True if we want to create R_MIPS_JALR for jalr $25. */
+#ifdef TE_IRIX
+#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
+#else
+/* As a GNU extension, we use R_MIPS_JALR for o32 too. However,
+ because there's no place for any addend, the only acceptable
+ expression is a bare symbol. */
+#define MIPS_JALR_HINT_P(EXPR) \
+ (!HAVE_IN_PLACE_ADDENDS \
+ || ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
+#endif
+
/* True if -mips3d was passed or implied by arguments passed on the
command line (e.g., by -march). */
static int file_ase_mips3d;
/* True if CPU has a ror instruction. */
#define CPU_HAS_ROR(CPU) CPU_HAS_DROR (CPU)
+/* True if CPU has seq/sne and seqi/snei instructions. */
+#define CPU_HAS_SEQ(CPU) ((CPU) == CPU_OCTEON)
+
+/* True if CPU does not implement the all the coprocessor insns. For these
+ CPUs only those COP insns are accepted that are explicitly marked to be
+ available on the CPU. ISA membership for COP insns is ignored. */
+#define NO_ISA_COP(CPU) ((CPU) == CPU_OCTEON)
+
/* True if mflo and mfhi can be immediately followed by instructions
which write to the HI and LO registers.
|| mips_opts.arch == CPU_R4010 \
|| mips_opts.arch == CPU_R10000 \
|| mips_opts.arch == CPU_R12000 \
+ || mips_opts.arch == CPU_R14000 \
+ || mips_opts.arch == CPU_R16000 \
|| mips_opts.arch == CPU_RM7000 \
|| mips_opts.arch == CPU_VR5500 \
)
/* Is this a mfhi or mflo instruction? */
#define MF_HILO_INSN(PINFO) \
- ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+ ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
+/* Returns true for a (non floating-point) coprocessor instruction. Reading
+ or writing the condition code is only possible on the coprocessors and
+ these insns are not marked with INSN_COP. Thus for these insns use the
+ condition-code flags. */
+#define COP_INSN(PINFO) \
+ (PINFO != INSN_MACRO \
+ && ((PINFO) & (FP_S | FP_D)) == 0 \
+ && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
/* MIPS PIC level. */
/* Classifies the kind of instructions we're interested in when
implementing -mfix-vr4120. */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
FIX_VR4120_MACC,
FIX_VR4120_DMACC,
FIX_VR4120_MULT,
NUM_FIX_VR4120_CLASSES
};
+/* ...likewise -mfix-loongson2f-jump. */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop. */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed. */
+static bfd_boolean mips_fix_loongson2f;
+
/* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
there must be at least one other instruction between an instruction
of type X and an instruction of type Y. */
/* ...likewise -mfix-vr4130. */
static int mips_fix_vr4130;
+/* ...likewise -mfix-24k. */
+static int mips_fix_24k;
+
/* We don't relax branches by default, since this causes us to expand
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we
fail to compute the offset before expanding the macro to the most
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
static void append_insn
- (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+ (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
static void mips16_macro_build
- (expressionS *, const char *, const char *, va_list);
+ (expressionS *, const char *, const char *, va_list *);
static void load_register (int, expressionS *, int);
static void macro_start (void);
static void macro_end (void);
};
static struct insn_label_list *free_insn_labels;
-#define label_list tc_segment_info_data
+#define label_list tc_segment_info_data.labels
static void mips_clear_insn_labels (void);
insn->mips16_absolute_jump_p = 0;
}
+/* Record the current MIPS16 mode in now_seg. */
+
+static void
+mips_record_mips16_mode (void)
+{
+ segment_info_type *si;
+
+ si = seg_info (now_seg);
+ if (si->tc_segment_info_data.mips16 != mips_opts.mips16)
+ si->tc_segment_info_data.mips16 = mips_opts.mips16;
+}
+
/* Install INSN at the location specified by its "frag" and "where" fields. */
static void
}
md_number_to_chars (f, insn->insn_opcode, 2);
}
+ mips_record_mips16_mode ();
}
/* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly
if (reg >= 0)
*s = e;
else if (types & RWARN)
- as_warn ("Unrecognized register name `%s'", *s);
+ as_warn (_("Unrecognized register name `%s'"), *s);
*e = save_c;
if (regnop)
return reg >= 0;
}
+/* Return TRUE if opcode MO is valid on the currently selected ISA and
+ architecture. Use is_opcode_valid_16 for MIPS16 opcodes. */
+
+static bfd_boolean
+is_opcode_valid (const struct mips_opcode *mo)
+{
+ int isa = mips_opts.isa;
+ int fp_s, fp_d;
+
+ if (mips_opts.ase_mdmx)
+ isa |= INSN_MDMX;
+ if (mips_opts.ase_dsp)
+ isa |= INSN_DSP;
+ if (mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
+ isa |= INSN_DSP64;
+ if (mips_opts.ase_dspr2)
+ isa |= INSN_DSPR2;
+ if (mips_opts.ase_mt)
+ isa |= INSN_MT;
+ if (mips_opts.ase_mips3d)
+ isa |= INSN_MIPS3D;
+ if (mips_opts.ase_smartmips)
+ isa |= INSN_SMARTMIPS;
+
+ /* Don't accept instructions based on the ISA if the CPU does not implement
+ all the coprocessor insns. */
+ if (NO_ISA_COP (mips_opts.arch)
+ && COP_INSN (mo->pinfo))
+ isa = 0;
+
+ if (!OPCODE_IS_MEMBER (mo, isa, mips_opts.arch))
+ return FALSE;
+
+ /* Check whether the instruction or macro requires single-precision or
+ double-precision floating-point support. Note that this information is
+ stored differently in the opcode table for insns and macros. */
+ if (mo->pinfo == INSN_MACRO)
+ {
+ fp_s = mo->pinfo2 & INSN2_M_FP_S;
+ fp_d = mo->pinfo2 & INSN2_M_FP_D;
+ }
+ else
+ {
+ fp_s = mo->pinfo & FP_S;
+ fp_d = mo->pinfo & FP_D;
+ }
+
+ if (fp_d && (mips_opts.soft_float || mips_opts.single_float))
+ return FALSE;
+
+ if (fp_s && mips_opts.soft_float)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return TRUE if the MIPS16 opcode MO is valid on the currently
+ selected ISA and architecture. */
+
+static bfd_boolean
+is_opcode_valid_16 (const struct mips_opcode *mo)
+{
+ return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
+}
+
/* This function is called once, at assembler startup time. It should set up
all the tables, etc. that the MD part of the assembler will need. */
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&nop_insn, mips_opcodes + i);
+ if (mips_fix_loongson2f_nop)
+ nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
}
helps us detect invalid uses of them. */
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,
+ reg_names[i].num, /* & RNUM_MASK, */
&zero_address_frag));
if (HAVE_NEWABI)
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,
+ reg_names_n32n64[i].num, /* & RNUM_MASK, */
&zero_address_frag));
else
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,
+ reg_names_o32[i].num, /* & RNUM_MASK, */
&zero_address_frag));
mips_no_prev_insn ();
/* On a native system other than VxWorks, sections must be aligned
to 16 byte boundaries. When configured for an embedded ELF
target, we don't bother. */
- if (strcmp (TARGET_OS, "elf") != 0
- && strcmp (TARGET_OS, "vxworks") != 0)
+ if (strncmp (TARGET_OS, "elf", 3) != 0
+ && strncmp (TARGET_OS, "vxworks", 7) != 0)
{
(void) bfd_set_section_alignment (stdoutput, text_section, 4);
(void) bfd_set_section_alignment (stdoutput, data_section, 4);
running program can access it. However, we don't load it
if we are configured for an embedded target */
flags = SEC_READONLY | SEC_DATA;
- if (strcmp (TARGET_OS, "elf") != 0)
+ if (strncmp (TARGET_OS, "elf", 3) != 0)
flags |= SEC_ALLOC | SEC_LOAD;
if (mips_abi != N64_ABI)
}
}
+/* Convenience functions for abstracting away the differences between
+ MIPS16 and non-MIPS16 relocations. */
+
+static inline bfd_boolean
+mips16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ switch (reloc)
+ {
+ case BFD_RELOC_MIPS16_JMP:
+ case BFD_RELOC_MIPS16_GPREL:
+ case BFD_RELOC_MIPS16_GOT16:
+ case BFD_RELOC_MIPS16_CALL16:
+ case BFD_RELOC_MIPS16_HI16_S:
+ case BFD_RELOC_MIPS16_HI16:
+ case BFD_RELOC_MIPS16_LO16:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static inline bfd_boolean
+got16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16;
+}
+
+static inline bfd_boolean
+hi16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S;
+}
+
+static inline bfd_boolean
+lo16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16;
+}
+
/* Return true if the given relocation might need a matching %lo().
This is only "might" because SVR4 R_MIPS_GOT16 relocations only
need a matching %lo() when applied to local symbols. */
reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
{
return (HAVE_IN_PLACE_ADDENDS
- && (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS16_HI16_S
+ && (hi16_reloc_p (reloc)
/* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
all GOT16 relocations evaluate to "G". */
- || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
+ || (got16_reloc_p (reloc) && mips_pic != VXWORKS_PIC)));
+}
+
+/* Return the type of %lo() reloc needed by RELOC, given that
+ reloc_needs_lo_p. */
+
+static inline bfd_reloc_code_real_type
+matching_lo_reloc (bfd_reloc_code_real_type reloc)
+{
+ return mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16 : BFD_RELOC_LO16;
}
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
fixup_has_matching_lo_p (fixS *fixp)
{
return (fixp->fx_next != NULL
- && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
- || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
+ && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
&& fixp->fx_addsy == fixp->fx_next->fx_addsy
&& fixp->fx_offset == fixp->fx_next->fx_offset);
}
static int
insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
- enum mips_regclass class)
+ enum mips_regclass regclass)
{
- if (class == MIPS16_REG)
+ if (regclass == MIPS16_REG)
{
- assert (mips_opts.mips16);
+ gas_assert (mips_opts.mips16);
reg = mips16_to_32_reg_map[reg];
- class = MIPS_GR_REG;
+ regclass = MIPS_GR_REG;
}
/* Don't report on general register ZERO, since it never changes. */
- if (class == MIPS_GR_REG && reg == ZERO)
+ if (regclass == MIPS_GR_REG && reg == ZERO)
return 0;
- if (class == MIPS_FP_REG)
+ if (regclass == MIPS_FP_REG)
{
- assert (! mips_opts.mips16);
+ gas_assert (! mips_opts.mips16);
/* If we are called with either $f0 or $f1, we must check $f0.
This is not optimal, because it will introduce an unnecessary
NOP between "lwc1 $f0" and "swc1 $f1". To fix this we would
for (l = si->label_list; l != NULL; l = l->next)
{
- assert (S_GET_SEGMENT (l->label) == now_seg);
+ gas_assert (S_GET_SEGMENT (l->label) == now_seg);
symbol_set_frag (l->label, frag_now);
val = (valueT) frag_now_fix ();
/* mips16 text labels are stored as odd. */
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
if (IS_ELF)
- S_SET_OTHER (label, STO_MIPS16);
+ S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
#endif
if ((S_GET_VALUE (label) & 1) == 0
/* Don't adjust the address if the label is global or weak, or
static void
relax_start (symbolS *symbol)
{
- assert (mips_relax.sequence == 0);
+ gas_assert (mips_relax.sequence == 0);
mips_relax.sequence = 1;
mips_relax.symbol = symbol;
}
static void
relax_switch (void)
{
- assert (mips_relax.sequence == 1);
+ gas_assert (mips_relax.sequence == 1);
mips_relax.sequence = 2;
}
static void
relax_end (void)
{
- assert (mips_relax.sequence == 2);
+ gas_assert (mips_relax.sequence == 2);
relax_close_frag ();
mips_relax.sequence = 0;
}
return NUM_FIX_VR4120_CLASSES;
}
+#define INSN_ERET 0x42000018
+#define INSN_DERET 0x4200001f
+
/* Return the number of instructions that must separate INSN1 and INSN2,
where INSN1 is the earlier instruction. Return the worst-case value
for any INSN2 if INSN2 is null. */
&& INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
return 2;
+ /* If we're working around 24K errata, one instruction is required
+ if an ERET or DERET is followed by a branch instruction. */
+ if (mips_fix_24k)
+ {
+ if (insn1->insn_opcode == INSN_ERET
+ || insn1->insn_opcode == INSN_DERET)
+ {
+ if (insn2 == NULL
+ || insn2->insn_opcode == INSN_ERET
+ || insn2->insn_opcode == INSN_DERET
+ || (insn2->insn_mo->pinfo
+ & (INSN_UNCOND_BRANCH_DELAY
+ | INSN_COND_BRANCH_DELAY
+ | INSN_COND_BRANCH_LIKELY)) != 0)
+ return 1;
+ }
+ }
+
/* If working around VR4120 errata, check for combinations that need
a single intervening instruction. */
if (mips_fix_vr4120)
/* Return the number of nops that would be needed to work around the
VR4130 mflo/mfhi errata if instruction INSN immediately followed
- the MAX_VR4130_NOPS instructions described by HISTORY. */
+ the MAX_VR4130_NOPS instructions described by HIST. */
static int
-nops_for_vr4130 (const struct mips_cl_insn *history,
+nops_for_vr4130 (const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
int i, j, reg;
/* Search for the first MFLO or MFHI. */
for (i = 0; i < MAX_VR4130_NOPS; i++)
- if (!history[i].noreorder_p && MF_HILO_INSN (history[i].insn_mo->pinfo))
+ if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
{
/* Extract the destination register. */
if (mips_opts.mips16)
- reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
+ reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, hist[i])];
else
- reg = EXTRACT_OPERAND (RD, history[i]);
+ reg = EXTRACT_OPERAND (RD, hist[i]);
/* No nops are needed if INSN reads that register. */
if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
/* ...or if any of the intervening instructions do. */
for (j = 0; j < i; j++)
- if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
+ if (insn_uses_reg (&hist[j], reg, MIPS_GR_REG))
return 0;
return MAX_VR4130_NOPS - i;
}
/* Return the number of nops that would be needed if instruction INSN
- immediately followed the MAX_NOPS instructions given by HISTORY,
- where HISTORY[0] is the most recent instruction. If INSN is null,
+ immediately followed the MAX_NOPS instructions given by HIST,
+ where HIST[0] is the most recent instruction. If INSN is null,
return the worse-case number of nops for any instruction. */
static int
-nops_for_insn (const struct mips_cl_insn *history,
+nops_for_insn (const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
int i, nops, tmp_nops;
nops = 0;
for (i = 0; i < MAX_DELAY_NOPS; i++)
- if (!history[i].noreorder_p)
- {
- tmp_nops = insns_between (history + i, insn) - i;
- if (tmp_nops > nops)
- nops = tmp_nops;
- }
+ {
+ tmp_nops = insns_between (hist + i, insn) - i;
+ if (tmp_nops > nops)
+ nops = tmp_nops;
+ }
if (mips_fix_vr4130)
{
- tmp_nops = nops_for_vr4130 (history, insn);
+ tmp_nops = nops_for_vr4130 (hist, insn);
if (tmp_nops > nops)
nops = tmp_nops;
}
}
/* The variable arguments provide NUM_INSNS extra instructions that
- might be added to HISTORY. Return the largest number of nops that
+ might be added to HIST. Return the largest number of nops that
would be needed after the extended sequence. */
static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
+nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
{
va_list args;
struct mips_cl_insn buffer[MAX_NOPS];
struct mips_cl_insn *cursor;
int nops;
- va_start (args, history);
+ va_start (args, hist);
cursor = buffer + num_insns;
- memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
+ memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
while (cursor > buffer)
*--cursor = *va_arg (args, const struct mips_cl_insn *);
worst-case delay for the branch target. */
static int
-nops_for_insn_or_target (const struct mips_cl_insn *history,
+nops_for_insn_or_target (const struct mips_cl_insn *hist,
const struct mips_cl_insn *insn)
{
int nops, tmp_nops;
- nops = nops_for_insn (history, insn);
+ nops = nops_for_insn (hist, insn);
if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
| INSN_COND_BRANCH_DELAY
| INSN_COND_BRANCH_LIKELY))
{
- tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
+ tmp_nops = nops_for_sequence (2, hist, insn, NOP_INSN);
if (tmp_nops > nops)
nops = tmp_nops;
}
- else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
+ else if (mips_opts.mips16
+ && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+ | MIPS16_INSN_COND_BRANCH)))
{
- tmp_nops = nops_for_sequence (1, history, insn);
+ tmp_nops = nops_for_sequence (1, hist, insn);
if (tmp_nops > nops)
nops = tmp_nops;
}
return nops;
}
+/* Fix NOP issue: Replace nops by "or at,at,zero". */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "nop") == 0)
+ ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+ jr target pc &= 'hffff_ffff_cfff_ffff. */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "j") == 0
+ || strcmp (ip->insn_mo->name, "jr") == 0
+ || strcmp (ip->insn_mo->name, "jalr") == 0)
+ {
+ int sreg;
+ expressionS ep;
+
+ if (! mips_opts.at)
+ return;
+
+ sreg = EXTRACT_OPERAND (RS, *ip);
+ if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+ return;
+
+ ep.X_op = O_constant;
+ ep.X_add_number = 0xcfff0000;
+ macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+ ep.X_add_number = 0xffff;
+ macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+ macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+ }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+ if (mips_fix_loongson2f_nop)
+ fix_loongson2f_nop (ip);
+
+ if (mips_fix_loongson2f_jump)
+ fix_loongson2f_jump (ip);
+}
+
/* Output an instruction. IP is the instruction information.
ADDRESS_EXPR is an operand of the instruction to be used with
RELOC_TYPE. */
bfd_boolean relaxed_branch = FALSE;
segment_info_type *si = seg_info (now_seg);
+ if (mips_fix_loongson2f)
+ fix_loongson2f (ip);
+
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
{
/* Work out how many nops in prev_nop_frag are needed by IP. */
int nops = nops_for_insn_or_target (history, ip);
- assert (nops <= prev_nop_frag_holds);
+ gas_assert (nops <= prev_nop_frag_holds);
/* Enforce NOPS as a minimum. */
if (nops > prev_nop_frag_required)
else if (*reloc_type > BFD_RELOC_UNUSED)
{
/* We need to set up a variant frag. */
- assert (mips_opts.mips16 && address_expr != NULL);
+ gas_assert (mips_opts.mips16 && address_expr != NULL);
add_relaxed_insn (ip, 4, 0,
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
break;
howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
+ if (howto == NULL)
+ {
+ /* To reproduce this failure try assembling gas/testsuites/
+ gas/mips/mips16-intermix.s with a mips-ecoff targeted
+ assembler. */
+ as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
+ howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
+ }
+
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
&& (reloc_type[0] == BFD_RELOC_16
|| reloc_type[0] == BFD_RELOC_32
|| reloc_type[0] == BFD_RELOC_MIPS_JMP
- || reloc_type[0] == BFD_RELOC_HI16_S
- || reloc_type[0] == BFD_RELOC_LO16
|| reloc_type[0] == BFD_RELOC_GPREL16
|| reloc_type[0] == BFD_RELOC_MIPS_LITERAL
|| reloc_type[0] == BFD_RELOC_GPREL32
|| reloc_type[0] == BFD_RELOC_MIPS_REL16
|| reloc_type[0] == BFD_RELOC_MIPS_RELGOT
|| reloc_type[0] == BFD_RELOC_MIPS16_GPREL
- || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
- || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
+ || hi16_reloc_p (reloc_type[0])
+ || lo16_reloc_p (reloc_type[0])))
ip->fixp[0]->fx_no_overflow = 1;
if (mips_relax.sequence)
|| (mips_opts.mips16 && history[0].fixp[0])
/* If the previous instruction is a sync, sync.l, or
sync.p, we can not swap. */
- || (prev_pinfo & INSN_SYNC))
+ || (prev_pinfo & INSN_SYNC)
+ /* If the previous instruction is an ERET or
+ DERET, avoid the swap. */
+ || (history[0].insn_opcode == INSN_ERET)
+ || (history[0].insn_opcode == INSN_DERET))
{
if (mips_opts.mips16
&& (pinfo & INSN_UNCOND_BRANCH_DELAY)
/* If that was an unconditional branch, forget the previous
insn information. */
if (pinfo & INSN_UNCOND_BRANCH_DELAY)
- mips_no_prev_insn ();
+ {
+ mips_no_prev_insn ();
+ }
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
{
static void
end_noreorder (void)
{
+
mips_opts.noreorder--;
if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
{
warning now. */
const char *msg = macro_warning (subtype);
if (msg != 0)
- as_warn (msg);
+ as_warn ("%s", msg);
}
else
{
if (mips_opts.mips16)
{
- mips16_macro_build (ep, name, fmt, args);
+ mips16_macro_build (ep, name, fmt, &args);
va_end (args);
return;
}
r[1] = BFD_RELOC_UNUSED;
r[2] = BFD_RELOC_UNUSED;
mo = (struct mips_opcode *) hash_find (op_hash, name);
- assert (mo);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo);
+ gas_assert (strcmp (name, mo->name) == 0);
while (1)
{
macros will never generate MDMX, MIPS-3D, or MT instructions. */
if (strcmp (fmt, mo->args) == 0
&& mo->pinfo != INSN_MACRO
- && OPCODE_IS_MEMBER (mo,
- (mips_opts.isa
- | (mips_opts.mips16 ? INSN_MIPS16 : 0)
- | (mips_opts.ase_dsp ? INSN_DSP : 0)
- | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
- ? INSN_DSP64 : 0)
- | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
- | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
- mips_opts.arch)
- && (mips_opts.arch != CPU_R4650 || (mo->pinfo & FP_D) == 0))
+ && is_opcode_valid (mo))
break;
++mo;
- assert (mo->name);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo->name);
+ gas_assert (strcmp (name, mo->name) == 0);
}
create_insn (&insn, mo);
INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
continue;
+ case 'Q':
+ INSERT_OPERAND (SEQI, insn, va_arg (args, int));
+ continue;
+
default:
internalError ();
}
case 'j':
case 'o':
macro_read_relocs (&args, r);
- assert (*r == BFD_RELOC_GPREL16
+ gas_assert (*r == BFD_RELOC_GPREL16
|| *r == BFD_RELOC_MIPS_LITERAL
|| *r == BFD_RELOC_MIPS_HIGHER
|| *r == BFD_RELOC_HI16_S
case 'u':
macro_read_relocs (&args, r);
- assert (ep != NULL
+ gas_assert (ep != NULL
&& (ep->X_op == O_constant
|| (ep->X_op == O_symbol
&& (*r == BFD_RELOC_MIPS_HIGHEST
continue;
case 'p':
- assert (ep != NULL);
+ gas_assert (ep != NULL);
/*
* This allows macro() to pass an immediate expression for
continue;
case 'a':
- assert (ep != NULL);
+ gas_assert (ep != NULL);
*r = BFD_RELOC_MIPS_JMP;
continue;
break;
}
va_end (args);
- assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (&insn, ep, r);
}
static void
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
- va_list args)
+ va_list *args)
{
struct mips_opcode *mo;
struct mips_cl_insn insn;
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
- assert (mo);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo);
+ gas_assert (strcmp (name, mo->name) == 0);
while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
{
++mo;
- assert (mo->name);
- assert (strcmp (name, mo->name) == 0);
+ gas_assert (mo->name);
+ gas_assert (strcmp (name, mo->name) == 0);
}
create_insn (&insn, mo);
case 'y':
case 'w':
- MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RY, insn, va_arg (*args, int));
continue;
case 'x':
case 'v':
- MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RX, insn, va_arg (*args, int));
continue;
case 'z':
- MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RZ, insn, va_arg (*args, int));
continue;
case 'Z':
- MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (*args, int));
continue;
case '0':
continue;
case 'X':
- MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
continue;
case 'Y':
{
int regno;
- regno = va_arg (args, int);
+ regno = va_arg (*args, int);
regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
MIPS16_INSERT_OPERAND (REG32R, insn, regno);
}
case 'p':
case 'q':
{
- assert (ep != NULL);
+ gas_assert (ep != NULL);
if (ep->X_op != O_constant)
*r = (int) BFD_RELOC_UNUSED + c;
continue;
case '6':
- MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (*args, int));
continue;
}
break;
}
- assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+ gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
append_insn (&insn, ep, r);
}
{
char *f = NULL;
- if (HAVE_NEWABI)
+ if (MIPS_JALR_HINT_P (ep))
{
frag_grow (8);
f = frag_more (0);
}
macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
- if (HAVE_NEWABI)
+ if (MIPS_JALR_HINT_P (ep))
fix_new_exp (frag_now, f - frag_now->fr_literal,
4, ep, FALSE, BFD_RELOC_MIPS_JALR);
}
const char *name = "lui";
const char *fmt = "t,u";
- assert (! mips_opts.mips16);
+ gas_assert (! mips_opts.mips16);
high_expr = *ep;
}
else
{
- assert (ep->X_op == O_symbol);
+ gas_assert (ep->X_op == O_symbol);
/* _gp_disp is a special case, used from s_cpload.
__gnu_local_gp is used if mips_no_shared. */
- assert (mips_pic == NO_PIC
+ gas_assert (mips_pic == NO_PIC
|| (! HAVE_NEWABI
&& strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
|| (! mips_in_shared
}
mo = hash_find (op_hash, name);
- assert (strcmp (name, mo->name) == 0);
- assert (strcmp (fmt, mo->args) == 0);
+ gas_assert (strcmp (name, mo->name) == 0);
+ gas_assert (strcmp (fmt, mo->args) == 0);
create_insn (&insn, mo);
insn.insn_opcode = insn.insn_mo->match;
macro_build_ldst_constoffset (expressionS *ep, const char *op,
int treg, int breg, int dbl)
{
- assert (ep->X_op == O_constant);
+ gas_assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
if (!dbl)
if (ep->X_op != O_big)
{
- assert (ep->X_op == O_constant);
+ gas_assert (ep->X_op == O_constant);
/* Sign-extending 32-bit constants makes their handling easier. */
if (!dbl)
}
else
{
- assert (ep->X_add_number > 2);
+ gas_assert (ep->X_add_number > 2);
if (ep->X_add_number == 3)
generic_bignum[3] = 0;
else if (ep->X_add_number > 4)
bfd_reloc_code_real_type r;
int hold_mips_optimize;
- assert (! mips_opts.mips16);
+ gas_assert (! mips_opts.mips16);
treg = (ip->insn_opcode >> 16) & 0x1f;
dreg = (ip->insn_opcode >> 11) & 0x1f;
s = "dinsm";
fmt = "t,r,+A,+F";
}
- macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
- pos + size - 1);
+ macro_build ((expressionS *) NULL, s, fmt, treg, sreg, (int) pos,
+ (int) (pos + size - 1));
}
break;
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
dreg = treg;
}
else
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
{
/* We must add in the base register now, as in the
external symbol case. */
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
load_delay_nop ();
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
}
else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
{
- int dreg;
-
/* If we are going to add in a base register, and the
target register and the base register are the same,
then we are using AT as a temporary register. Since
dreg = tempreg;
else
{
- assert (tempreg == AT);
+ gas_assert (tempreg == AT);
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
treg, AT, breg);
dreg = treg;
macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
break;
+ case M_MSGSND:
+ {
+ unsigned long temp = (treg << 16) | (0x01);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ /* AT is not used, just return */
+ return;
+
+ case M_MSGLD:
+ {
+ unsigned long temp = (0x02);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ /* AT is not used, just return */
+ return;
+
+ case M_MSGLD_T:
+ {
+ unsigned long temp = (treg << 16) | (0x02);
+ macro_build (NULL, "c2", "C", temp);
+ }
+ /* AT is not used, just return */
+ return;
+
+ case M_MSGWAIT:
+ macro_build (NULL, "c2", "C", 3);
+ /* AT is not used, just return */
+ return;
+
+ case M_MSGWAIT_T:
+ {
+ unsigned long temp = (treg << 16) | 0x03;
+ macro_build (NULL, "c2", "C", temp);
+ }
+ /* AT is not used, just return */
+ return;
+
case M_J_A:
/* The j instruction may not be used in PIC code, since it
requires an absolute address. We convert it to a b
/* Quiet this warning. */
mips_cprestore_valid = 1;
}
+ if (mips_opts.noreorder)
+ macro_build (NULL, "nop", "");
expr1.X_add_number = mips_cprestore_offset;
macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
mips_gp_register,
lr = 1;
goto ld;
case M_LDC1_AB:
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
s = "ldc1";
/* Itbl support may require additional care here. */
coproc = 1;
s = "cache";
goto st;
case M_SDC1_AB:
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
s = "sdc1";
coproc = 1;
/* Itbl support may require additional care here. */
tempreg = AT;
used_at = 1;
ld_st:
+ if (coproc
+ && NO_ISA_COP (mips_opts.arch)
+ && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
+ {
+ as_bad (_("opcode not supported on this processor: %s"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name);
+ break;
+ }
+
/* Itbl support may require additional care here. */
if (mask == M_LWC1_AB
|| mask == M_SWC1_AB
16 bits, because we have no way to load the upper 16 bits
(actually, we could handle them for the subset of cases
in which we are not using $at). */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
if (HAVE_NEWABI)
{
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
16 bits, because we have no way to load the upper 16 bits
(actually, we could handle them for the subset of cases
in which we are not using $at). */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
if (expr1.X_add_number < -0x8000
Otherwise, for local symbols, we want:
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
<op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */
- assert (offset_expr.X_op == O_symbol);
+ gas_assert (offset_expr.X_op == O_symbol);
expr1.X_add_number = offset_expr.X_add_number;
offset_expr.X_add_number = 0;
if (expr1.X_add_number < -0x8000
}
else
{
- assert (offset_expr.X_op == O_symbol
+ gas_assert (offset_expr.X_op == O_symbol
&& strcmp (segment_name (S_GET_SEGMENT
(offset_expr.X_add_symbol)),
".lit4") == 0
move_register (lreg, 0);
else
{
- assert (offset_expr.X_op == O_constant);
+ gas_assert (offset_expr.X_op == O_constant);
load_register (lreg, &offset_expr, 0);
}
}
load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
if (HAVE_64BIT_FPRS)
{
- assert (HAVE_64BIT_GPRS);
+ gas_assert (HAVE_64BIT_GPRS);
macro_build (NULL, "dmtc1", "t,S", AT, treg);
}
else
macro_build (NULL, "mtc1", "t,G", 0, treg);
else
{
- assert (offset_expr.X_op == O_constant);
+ gas_assert (offset_expr.X_op == O_constant);
load_register (AT, &offset_expr, 0);
macro_build (NULL, "mtc1", "t,G", AT, treg);
}
break;
}
- assert (offset_expr.X_op == O_symbol
+ gas_assert (offset_expr.X_op == O_symbol
&& offset_expr.X_add_number == 0);
s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
if (strcmp (s, ".lit8") == 0)
}
else
{
- assert (strcmp (s, RDATA_SECTION_NAME) == 0);
+ gas_assert (strcmp (s, RDATA_SECTION_NAME) == 0);
used_at = 1;
if (mips_pic != NO_PIC)
macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
}
case M_L_DOB:
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
/* Even on a big endian machine $fn comes before $fn+1. We have
to adjust when loading from memory. */
r = BFD_RELOC_LO16;
dob:
- assert (mips_opts.isa == ISA_MIPS1);
+ gas_assert (mips_opts.isa == ISA_MIPS1);
macro_build (&offset_expr, "lwc1", "T,o(b)",
target_big_endian ? treg + 1 : treg, r, breg);
/* FIXME: A possible overflow which I don't know how to deal
* But, the resulting address is the same after relocation so why
* generate the extra instruction?
*/
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
/* Itbl support may require additional care here. */
coproc = 1;
if (mips_opts.isa != ISA_MIPS1)
goto ldd_std;
case M_S_DAB:
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
-
if (mips_opts.isa != ISA_MIPS1)
{
s = "sdc1";
case M_SD_OB:
s = "sw";
sd_ob:
- assert (HAVE_32BIT_ADDRESSES);
+ gas_assert (HAVE_32BIT_ADDRESSES);
macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
offset_expr.X_add_number += 4;
macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
case M_COP3:
s = "c3";
copz:
+ if (NO_ISA_COP (mips_opts.arch)
+ && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
+ {
+ as_bad (_("opcode not supported on this processor: %s"),
+ mips_cpu_info_from_arch (mips_opts.arch)->name);
+ break;
+ }
+
/* For now we just do C (same as Cz). The parameter will be
stored in insn_opcode by mips_ip. */
macro_build (NULL, s, "C", ip->insn_opcode);
case M_DROL_I:
{
unsigned int rot;
- char *l, *r;
+ char *l;
+ char *rr;
if (imm_expr.X_op != O_constant)
as_bad (_("Improper rotate count"));
break;
}
l = (rot < 0x20) ? "dsll" : "dsll32";
- r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
+ rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
rot &= 0x1f;
used_at = 1;
macro_build (NULL, l, "d,w,<", AT, sreg, rot);
- macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+ macro_build (NULL, rr, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
}
break;
case M_DROR_I:
{
unsigned int rot;
- char *l, *r;
+ char *l;
+ char *rr;
if (imm_expr.X_op != O_constant)
as_bad (_("Improper rotate count"));
macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
break;
}
- r = (rot < 0x20) ? "dsrl" : "dsrl32";
+ rr = (rot < 0x20) ? "dsrl" : "dsrl32";
l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
rot &= 0x1f;
used_at = 1;
- macro_build (NULL, r, "d,w,<", AT, sreg, rot);
+ macro_build (NULL, rr, "d,w,<", AT, sreg, rot);
macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
}
break;
case M_S_DOB:
- if (mips_opts.arch == CPU_R4650)
- {
- as_bad (_("opcode not supported on this processor"));
- break;
- }
- assert (mips_opts.isa == ISA_MIPS1);
+ gas_assert (mips_opts.isa == ISA_MIPS1);
/* Even on a big endian machine $fn comes before $fn+1. We have
to adjust when storing to memory. */
macro_build (&offset_expr, "swc1", "T,o(b)",
move_register (dreg, 0);
break;
}
+ if (CPU_HAS_SEQ (mips_opts.arch)
+ && -512 <= imm_expr.X_add_number
+ && imm_expr.X_add_number < 512)
+ {
+ macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+ (int) imm_expr.X_add_number);
+ break;
+ }
if (imm_expr.X_op == O_constant
&& imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
"t,r,j", dreg, sreg, BFD_RELOC_LO16);
}
+ else if (CPU_HAS_SEQ (mips_opts.arch))
+ {
+ used_at = 1;
+ load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+ break;
+ }
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
dreg, 0, BFD_RELOC_LO16);
break;
}
+ if (CPU_HAS_SEQ (mips_opts.arch)
+ && -512 <= imm_expr.X_add_number
+ && imm_expr.X_add_number < 512)
+ {
+ macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+ (int) imm_expr.X_add_number);
+ break;
+ }
if (imm_expr.X_op == O_constant
&& imm_expr.X_add_number >= 0
&& imm_expr.X_add_number < 0x10000)
macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
"t,r,j", dreg, sreg, BFD_RELOC_LO16);
}
+ else if (CPU_HAS_SEQ (mips_opts.arch))
+ {
+ used_at = 1;
+ load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+ macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+ break;
+ }
else
{
load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
case M_TRUNCWS:
case M_TRUNCWD:
- assert (mips_opts.isa == ISA_MIPS1);
+ gas_assert (mips_opts.isa == ISA_MIPS1);
used_at = 1;
sreg = (ip->insn_opcode >> 11) & 0x1f; /* floating reg */
dreg = (ip->insn_opcode >> 06) & 0x1f; /* floating reg */
case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
case 'T': USE_BITS (OP_MASK_RT, OP_SH_RT);
USE_BITS (OP_MASK_SEL, OP_SH_SEL); break;
+ case 'x': USE_BITS (OP_MASK_BBITIND, OP_SH_BBITIND); break;
+ case 'X': USE_BITS (OP_MASK_BBITIND, OP_SH_BBITIND); break;
+ case 'p': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
+ case 'P': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
+ case 'Q': USE_BITS (OP_MASK_SEQI, OP_SH_SEQI); break;
+ case 's': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
+ case 'S': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
+
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
c, opc->name, opc->args);
case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break;
case '[': break;
case ']': break;
+ case '1': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
case '2': USE_BITS (OP_MASK_BP, OP_SH_BP); break;
case '3': USE_BITS (OP_MASK_SA3, OP_SH_SA3); break;
case '4': USE_BITS (OP_MASK_SA4, OP_SH_SA4); break;
/* If we did not find a '.', then we can quit now. */
if (*s != '.')
{
- insn_error = "unrecognized opcode";
+ insn_error = _("unrecognized opcode");
return;
}
*s++ = '\0';
if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
{
- insn_error = "unrecognized opcode";
+ insn_error = _("unrecognized opcode");
return;
}
}
{
bfd_boolean ok;
- assert (strcmp (insn->name, str) == 0);
-
- if (OPCODE_IS_MEMBER (insn,
- (mips_opts.isa
- /* We don't check for mips_opts.mips16 here since
- we want to allow jalx if -mips16 was specified
- on the command line. */
- | (file_ase_mips16 ? INSN_MIPS16 : 0)
- | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
- | (mips_opts.ase_dsp ? INSN_DSP : 0)
- | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
- ? INSN_DSP64 : 0)
- | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
- | (mips_opts.ase_mt ? INSN_MT : 0)
- | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)
- | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
- mips_opts.arch))
- ok = TRUE;
- else
- ok = FALSE;
-
- if (insn->pinfo != INSN_MACRO)
- {
- if (mips_opts.arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
- ok = FALSE;
- }
+ gas_assert (strcmp (insn->name, str) == 0);
+ ok = is_opcode_valid (insn);
if (! ok)
{
if (insn + 1 < &mips_opcodes[NUMOPCODES]
create_insn (ip, insn);
insn_error = NULL;
argnum = 1;
+ lastregno = 0xffffffff;
for (args = insn->args;; ++args)
{
int is_mdmx;
we must have a left paren. */
/* This is dependent on the next operand specifier
is a base register specification. */
- assert (args[1] == 'b' || args[1] == '5'
+ gas_assert (args[1] == 'b' || args[1] == '5'
|| args[1] == '-' || args[1] == '4');
if (*s == '\0')
return;
as_bad (_("Invalid coprocessor 0 register number"));
break;
+ case 'x':
+ /* bbit[01] and bbit[01]32 bit index. Give error if index
+ is not in the valid range. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned) imm_expr.X_add_number > 31)
+ {
+ as_bad (_("Improper bit index (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'X':
+ /* bbit[01] bit index when bbit is used but we generate
+ bbit[01]32 because the index is over 32. Move to the
+ next candidate if index is not in the valid range. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned) imm_expr.X_add_number < 32
+ || (unsigned) imm_expr.X_add_number > 63)
+ break;
+ INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number - 32);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'p':
+ /* cins, cins32, exts and exts32 position field. Give error
+ if it's not in the valid range. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned) imm_expr.X_add_number > 31)
+ {
+ as_bad (_("Improper position (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ /* Make the pos explicit to simplify +S. */
+ lastpos = imm_expr.X_add_number + 32;
+ INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'P':
+ /* cins, cins32, exts and exts32 position field. Move to
+ the next candidate if it's not in the valid range. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned) imm_expr.X_add_number < 32
+ || (unsigned) imm_expr.X_add_number > 63)
+ break;
+ lastpos = imm_expr.X_add_number;
+ INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number - 32);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 's':
+ /* cins and exts length-minus-one field. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > 31)
+ {
+ as_bad (_("Improper size (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'S':
+ /* cins32/exts32 and cins/exts aliasing cint32/exts32
+ length-minus-one field. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((long) imm_expr.X_add_number < 0
+ || (unsigned long) imm_expr.X_add_number + lastpos > 63)
+ {
+ as_bad (_("Improper size (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'Q':
+ /* seqi/snei immediate field. */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((long) imm_expr.X_add_number < -512
+ || (long) imm_expr.X_add_number >= 512)
+ {
+ as_bad (_("Improper immediate (%ld)"),
+ (long) imm_expr.X_add_number);
+ imm_expr.X_add_number = 0;
+ }
+ INSERT_OPERAND (SEQI, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
default:
as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
*args, insn->name, insn->args);
case 'k': /* cache code */
case 'h': /* prefx code */
+ case '1': /* sync type */
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > 31)
(unsigned long) imm_expr.X_add_number);
if (*args == 'k')
INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
- else
+ else if (*args == 'h')
INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
+ else
+ INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
s = expr_end;
continue;
if (c == 'z' && regno != 0)
break;
+ if (c == 's' && !strncmp (ip->insn_mo->name, "jalr", 4))
+ {
+ if (regno == lastregno)
+ {
+ insn_error = _("source and destination must be different");
+ continue;
+ }
+ if (regno == 31 && lastregno == 0xffffffff)
+ {
+ insn_error = _("a destination register must be supplied");
+ continue;
+ }
+ }
/* Now that we have assembled one operand, we use the args string
* to figure out where it goes in the instruction. */
switch (c)
my_getExpression (&imm_expr, s);
check_absolute_expr (ip, &imm_expr);
if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
- as_warn ("Improper align amount (%ld), using low bits",
+ as_warn (_("Improper align amount (%ld), using low bits"),
(long) imm_expr.X_add_number);
INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
imm_expr.X_op = O_absent;
check_absolute_expr (ip, &imm_expr);
s = expr_end;
if (imm_expr.X_add_number > max_el)
- as_bad(_("Bad element selector %ld"),
- (long) imm_expr.X_add_number);
+ as_bad (_("Bad element selector %ld"),
+ (long) imm_expr.X_add_number);
imm_expr.X_add_number &= max_el;
ip->insn_opcode |= (imm_expr.X_add_number
<< (OP_SH_VSEL +
(is_qh ? 2 : 1)));
imm_expr.X_op = O_absent;
if (*s != ']')
- as_warn(_("Expecting ']' found '%s'"), s);
+ as_warn (_("Expecting ']' found '%s'"), s);
else
s++;
}
length = f64 ? 8 : 4;
}
- assert (length == (unsigned) (f64 ? 8 : 4));
+ gas_assert (length == (unsigned) (f64 ? 8 : 4));
if (*args == 'f'
|| (*args == 'l'
newname = RDATA_SECTION_NAME;
break;
case 'l':
- assert (g_switch_value >= 4);
+ gas_assert (g_switch_value >= 4);
newname = ".lit4";
break;
}
| SEC_READONLY
| SEC_DATA));
frag_align (*args == 'l' ? 2 : 3, 0, 0);
- if (IS_ELF && strcmp (TARGET_OS, "elf") != 0)
+ if (IS_ELF && strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (new_seg, 4);
else
record_alignment (new_seg, *args == 'l' ? 2 : 3);
/* Set the argument to the current address in the
section. */
offset_expr.X_op = O_symbol;
- offset_expr.X_add_symbol =
- symbol_new ("L0\001", now_seg,
- (valueT) frag_now_fix (), frag_now);
+ offset_expr.X_add_symbol = symbol_temp_new_now ();
offset_expr.X_add_number = 0;
/* Put the floating point number into the section. */
|| strcmp(str + strlen(str) - 5, "any2f") == 0
|| strcmp(str + strlen(str) - 5, "any2t") == 0)
&& (regno & 1) != 0)
- as_warn(_("Condition code register should be even for %s, was %d"),
- str, regno);
+ as_warn (_("Condition code register should be even for %s, was %d"),
+ str, regno);
if ((strcmp(str + strlen(str) - 5, "any4f") == 0
|| strcmp(str + strlen(str) - 5, "any4t") == 0)
&& (regno & 3) != 0)
- as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
- str, regno);
+ as_warn (_("Condition code register should be 0 or 4 for %s, was %d"),
+ str, regno);
if (*args == 'N')
INSERT_OPERAND (BCC, *ip, regno);
else
continue;
}
if (save_c)
- *(--s) = save_c;
+ *(--argsStart) = save_c;
insn_error = _("illegal operands");
return;
}
{
bfd_boolean ok;
- assert (strcmp (insn->name, str) == 0);
-
- if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
- ok = TRUE;
- else
- ok = FALSE;
+ gas_assert (strcmp (insn->name, str) == 0);
+ ok = is_opcode_valid_16 (insn);
if (! ok)
{
if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
/* Stuff the immediate value in now, if we can. */
if (imm_expr.X_op == O_constant
&& *imm_reloc > BFD_RELOC_UNUSED
+ && *imm_reloc != BFD_RELOC_MIPS16_GOT16
+ && *imm_reloc != BFD_RELOC_MIPS16_CALL16
&& insn->pinfo != INSN_MACRO)
{
valueT tmp;
{
int opcode = 0;
int framesz = 0, seen_framesz = 0;
- int args = 0, statics = 0, sregs = 0;
+ int nargs = 0, statics = 0, sregs = 0;
while (*s != '\0')
{
{
if (!seen_framesz)
/* args $a0-$a3 */
- args |= 1 << (reg1 - 4);
+ nargs |= 1 << (reg1 - 4);
else
/* statics $a0-$a3 */
statics |= 1 << (reg1 - 4);
}
/* Encode args/statics combination. */
- if (args & statics)
+ if (nargs & statics)
as_bad (_("arg/static registers overlap"));
- else if (args == 0xf)
+ else if (nargs == 0xf)
/* All $a0-$a3 are args. */
opcode |= MIPS16_ALL_ARGS << 16;
else if (statics == 0xf)
int narg = 0, nstat = 0;
/* Count arg registers. */
- while (args & 0x1)
+ while (nargs & 0x1)
{
- args >>= 1;
+ nargs >>= 1;
narg++;
}
- if (args != 0)
+ if (nargs != 0)
as_bad (_("invalid arg register list"));
/* Count static registers. */
while (op->type != type)
{
++op;
- assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+ gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
}
if (op->unsp)
{
{"%lo", BFD_RELOC_MIPS16_LO16},
{"%gprel", BFD_RELOC_MIPS16_GPREL},
+ {"%got", BFD_RELOC_MIPS16_GOT16},
+ {"%call16", BFD_RELOC_MIPS16_CALL16},
{"%hi", BFD_RELOC_MIPS16_HI16_S}
};
If not, issue an error and fall back on something safe. */
if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
{
- as_bad ("relocation %s isn't supported by the current ABI",
+ as_bad (_("relocation %s isn't supported by the current ABI"),
percent_op[i].str);
*reloc = BFD_RELOC_UNUSED;
}
crux_depth--;
if (crux_depth > 0)
- as_bad ("unclosed '('");
+ as_bad (_("unclosed '('"));
expr_end = str;
const char *md_shortopts = "O::g::G:";
+enum options
+ {
+ OPTION_MARCH = OPTION_MD_BASE,
+ OPTION_MTUNE,
+ OPTION_MIPS1,
+ OPTION_MIPS2,
+ OPTION_MIPS3,
+ OPTION_MIPS4,
+ OPTION_MIPS5,
+ OPTION_MIPS32,
+ OPTION_MIPS64,
+ OPTION_MIPS32R2,
+ OPTION_MIPS64R2,
+ OPTION_MIPS16,
+ OPTION_NO_MIPS16,
+ OPTION_MIPS3D,
+ OPTION_NO_MIPS3D,
+ OPTION_MDMX,
+ OPTION_NO_MDMX,
+ OPTION_DSP,
+ OPTION_NO_DSP,
+ OPTION_MT,
+ OPTION_NO_MT,
+ OPTION_SMARTMIPS,
+ OPTION_NO_SMARTMIPS,
+ OPTION_DSPR2,
+ OPTION_NO_DSPR2,
+ OPTION_COMPAT_ARCH_BASE,
+ OPTION_M4650,
+ OPTION_NO_M4650,
+ OPTION_M4010,
+ OPTION_NO_M4010,
+ OPTION_M4100,
+ OPTION_NO_M4100,
+ OPTION_M3900,
+ OPTION_NO_M3900,
+ OPTION_M7000_HILO_FIX,
+ OPTION_MNO_7000_HILO_FIX,
+ OPTION_FIX_24K,
+ OPTION_NO_FIX_24K,
+ OPTION_FIX_LOONGSON2F_JUMP,
+ OPTION_NO_FIX_LOONGSON2F_JUMP,
+ OPTION_FIX_LOONGSON2F_NOP,
+ OPTION_NO_FIX_LOONGSON2F_NOP,
+ OPTION_FIX_VR4120,
+ OPTION_NO_FIX_VR4120,
+ OPTION_FIX_VR4130,
+ OPTION_NO_FIX_VR4130,
+ OPTION_TRAP,
+ OPTION_BREAK,
+ OPTION_EB,
+ OPTION_EL,
+ OPTION_FP32,
+ OPTION_GP32,
+ OPTION_CONSTRUCT_FLOATS,
+ OPTION_NO_CONSTRUCT_FLOATS,
+ OPTION_FP64,
+ OPTION_GP64,
+ OPTION_RELAX_BRANCH,
+ OPTION_NO_RELAX_BRANCH,
+ OPTION_MSHARED,
+ OPTION_MNO_SHARED,
+ OPTION_MSYM32,
+ OPTION_MNO_SYM32,
+ OPTION_SOFT_FLOAT,
+ OPTION_HARD_FLOAT,
+ OPTION_SINGLE_FLOAT,
+ OPTION_DOUBLE_FLOAT,
+ OPTION_32,
+#ifdef OBJ_ELF
+ OPTION_CALL_SHARED,
+ OPTION_CALL_NONPIC,
+ OPTION_NON_SHARED,
+ OPTION_XGOT,
+ OPTION_MABI,
+ OPTION_N32,
+ OPTION_64,
+ OPTION_MDEBUG,
+ OPTION_NO_MDEBUG,
+ OPTION_PDR,
+ OPTION_NO_PDR,
+ OPTION_MVXWORKS_PIC,
+#endif /* OBJ_ELF */
+ OPTION_END_OF_ENUM
+ };
+
struct option md_longopts[] =
{
/* Options which specify architecture. */
-#define OPTION_ARCH_BASE (OPTION_MD_BASE)
-#define OPTION_MARCH (OPTION_ARCH_BASE + 0)
{"march", required_argument, NULL, OPTION_MARCH},
-#define OPTION_MTUNE (OPTION_ARCH_BASE + 1)
{"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_MIPS1 (OPTION_ARCH_BASE + 2)
{"mips0", no_argument, NULL, OPTION_MIPS1},
{"mips1", no_argument, NULL, OPTION_MIPS1},
-#define OPTION_MIPS2 (OPTION_ARCH_BASE + 3)
{"mips2", no_argument, NULL, OPTION_MIPS2},
-#define OPTION_MIPS3 (OPTION_ARCH_BASE + 4)
{"mips3", no_argument, NULL, OPTION_MIPS3},
-#define OPTION_MIPS4 (OPTION_ARCH_BASE + 5)
{"mips4", no_argument, NULL, OPTION_MIPS4},
-#define OPTION_MIPS5 (OPTION_ARCH_BASE + 6)
{"mips5", no_argument, NULL, OPTION_MIPS5},
-#define OPTION_MIPS32 (OPTION_ARCH_BASE + 7)
{"mips32", no_argument, NULL, OPTION_MIPS32},
-#define OPTION_MIPS64 (OPTION_ARCH_BASE + 8)
{"mips64", no_argument, NULL, OPTION_MIPS64},
-#define OPTION_MIPS32R2 (OPTION_ARCH_BASE + 9)
{"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
-#define OPTION_MIPS64R2 (OPTION_ARCH_BASE + 10)
{"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
/* Options which specify Application Specific Extensions (ASEs). */
-#define OPTION_ASE_BASE (OPTION_ARCH_BASE + 11)
-#define OPTION_MIPS16 (OPTION_ASE_BASE + 0)
{"mips16", no_argument, NULL, OPTION_MIPS16},
-#define OPTION_NO_MIPS16 (OPTION_ASE_BASE + 1)
{"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-#define OPTION_MIPS3D (OPTION_ASE_BASE + 2)
{"mips3d", no_argument, NULL, OPTION_MIPS3D},
-#define OPTION_NO_MIPS3D (OPTION_ASE_BASE + 3)
{"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
-#define OPTION_MDMX (OPTION_ASE_BASE + 4)
{"mdmx", no_argument, NULL, OPTION_MDMX},
-#define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
{"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
-#define OPTION_DSP (OPTION_ASE_BASE + 6)
{"mdsp", no_argument, NULL, OPTION_DSP},
-#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
{"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
-#define OPTION_MT (OPTION_ASE_BASE + 8)
{"mmt", no_argument, NULL, OPTION_MT},
-#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
{"mno-mt", no_argument, NULL, OPTION_NO_MT},
-#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10)
{"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
-#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11)
{"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
-#define OPTION_DSPR2 (OPTION_ASE_BASE + 12)
{"mdspr2", no_argument, NULL, OPTION_DSPR2},
-#define OPTION_NO_DSPR2 (OPTION_ASE_BASE + 13)
{"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
/* Old-style architecture options. Don't add more of these. */
-#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 14)
-#define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
{"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
{"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-#define OPTION_M4010 (OPTION_COMPAT_ARCH_BASE + 2)
{"m4010", no_argument, NULL, OPTION_M4010},
-#define OPTION_NO_M4010 (OPTION_COMPAT_ARCH_BASE + 3)
{"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-#define OPTION_M4100 (OPTION_COMPAT_ARCH_BASE + 4)
{"m4100", no_argument, NULL, OPTION_M4100},
-#define OPTION_NO_M4100 (OPTION_COMPAT_ARCH_BASE + 5)
{"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-#define OPTION_M3900 (OPTION_COMPAT_ARCH_BASE + 6)
{"m3900", no_argument, NULL, OPTION_M3900},
-#define OPTION_NO_M3900 (OPTION_COMPAT_ARCH_BASE + 7)
{"no-m3900", no_argument, NULL, OPTION_NO_M3900},
/* Options which enable bug fixes. */
-#define OPTION_FIX_BASE (OPTION_COMPAT_ARCH_BASE + 8)
-#define OPTION_M7000_HILO_FIX (OPTION_FIX_BASE + 0)
{"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-#define OPTION_MNO_7000_HILO_FIX (OPTION_FIX_BASE + 1)
{"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
{"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-#define OPTION_FIX_VR4120 (OPTION_FIX_BASE + 2)
-#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
+ {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+ {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+ {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+ {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
{"mfix-vr4120", no_argument, NULL, OPTION_FIX_VR4120},
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
-#define OPTION_FIX_VR4130 (OPTION_FIX_BASE + 4)
-#define OPTION_NO_FIX_VR4130 (OPTION_FIX_BASE + 5)
{"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130},
{"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
+ {"mfix-24k", no_argument, NULL, OPTION_FIX_24K},
+ {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
/* Miscellaneous options. */
-#define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
-#define OPTION_TRAP (OPTION_MISC_BASE + 0)
{"trap", no_argument, NULL, OPTION_TRAP},
{"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MISC_BASE + 1)
{"break", no_argument, NULL, OPTION_BREAK},
{"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MISC_BASE + 2)
{"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MISC_BASE + 3)
{"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_FP32 (OPTION_MISC_BASE + 4)
{"mfp32", no_argument, NULL, OPTION_FP32},
-#define OPTION_GP32 (OPTION_MISC_BASE + 5)
{"mgp32", no_argument, NULL, OPTION_GP32},
-#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 6)
{"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
{"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-#define OPTION_FP64 (OPTION_MISC_BASE + 8)
{"mfp64", no_argument, NULL, OPTION_FP64},
-#define OPTION_GP64 (OPTION_MISC_BASE + 9)
{"mgp64", no_argument, NULL, OPTION_GP64},
-#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 10)
-#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 11)
{"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
{"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
-#define OPTION_MSHARED (OPTION_MISC_BASE + 12)
-#define OPTION_MNO_SHARED (OPTION_MISC_BASE + 13)
{"mshared", no_argument, NULL, OPTION_MSHARED},
{"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
-#define OPTION_MSYM32 (OPTION_MISC_BASE + 14)
-#define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15)
{"msym32", no_argument, NULL, OPTION_MSYM32},
{"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
-
+ {"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
+ {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
+ {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
+ {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+
+ /* Strictly speaking this next option is ELF specific,
+ but we allow it for other ports as well in order to
+ make testing easier. */
+ {"32", no_argument, NULL, OPTION_32},
+
/* ELF-specific options. */
#ifdef OBJ_ELF
-#define OPTION_ELF_BASE (OPTION_MISC_BASE + 16)
-#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
{"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_NON_SHARED (OPTION_ELF_BASE + 1)
+ {"call_nonpic", no_argument, NULL, OPTION_CALL_NONPIC},
{"non_shared", no_argument, NULL, OPTION_NON_SHARED},
-#define OPTION_XGOT (OPTION_ELF_BASE + 2)
{"xgot", no_argument, NULL, OPTION_XGOT},
-#define OPTION_MABI (OPTION_ELF_BASE + 3)
{"mabi", required_argument, NULL, OPTION_MABI},
-#define OPTION_32 (OPTION_ELF_BASE + 4)
- {"32", no_argument, NULL, OPTION_32},
-#define OPTION_N32 (OPTION_ELF_BASE + 5)
{"n32", no_argument, NULL, OPTION_N32},
-#define OPTION_64 (OPTION_ELF_BASE + 6)
{"64", no_argument, NULL, OPTION_64},
-#define OPTION_MDEBUG (OPTION_ELF_BASE + 7)
{"mdebug", no_argument, NULL, OPTION_MDEBUG},
-#define OPTION_NO_MDEBUG (OPTION_ELF_BASE + 8)
{"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
-#define OPTION_PDR (OPTION_ELF_BASE + 9)
{"mpdr", no_argument, NULL, OPTION_PDR},
-#define OPTION_NO_PDR (OPTION_ELF_BASE + 10)
{"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
-#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11)
{"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
#endif /* OBJ_ELF */
break;
case 'O':
- if (arg && arg[0] == '0')
+ if (arg == NULL)
+ mips_optimize = 1;
+ else if (arg[0] == '0')
+ mips_optimize = 0;
+ else if (arg[0] == '1')
mips_optimize = 1;
else
mips_optimize = 2;
mips_opts.ase_smartmips = 0;
break;
+ case OPTION_FIX_24K:
+ mips_fix_24k = 1;
+ break;
+
+ case OPTION_NO_FIX_24K:
+ mips_fix_24k = 0;
+ break;
+
+ case OPTION_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = FALSE;
+ break;
+
+ case OPTION_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = FALSE;
+ break;
+
case OPTION_FIX_VR4120:
mips_fix_vr4120 = 1;
break;
mips_abicalls = TRUE;
break;
+ case OPTION_CALL_NONPIC:
+ if (!IS_ELF)
+ {
+ as_bad (_("-call_nonpic is supported only for ELF format"));
+ return 0;
+ }
+ mips_pic = NO_PIC;
+ mips_abicalls = TRUE;
+ break;
+
case OPTION_NON_SHARED:
if (!IS_ELF)
{
g_switch_seen = 1;
break;
-#ifdef OBJ_ELF
/* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
and -mabi=64. */
case OPTION_32:
- if (!IS_ELF)
- {
- as_bad (_("-32 is supported for ELF format only"));
- return 0;
- }
- mips_abi = O32_ABI;
+ if (IS_ELF)
+ mips_abi = O32_ABI;
+ /* We silently ignore -32 for non-ELF targets. This greatly
+ simplifies the construction of the MIPS GAS test cases. */
break;
+#ifdef OBJ_ELF
case OPTION_N32:
if (!IS_ELF)
{
file_mips_fp32 = 0;
break;
+ case OPTION_SINGLE_FLOAT:
+ file_mips_single_float = 1;
+ break;
+
+ case OPTION_DOUBLE_FLOAT:
+ file_mips_single_float = 0;
+ break;
+
+ case OPTION_SOFT_FLOAT:
+ file_mips_soft_float = 1;
+ break;
+
+ case OPTION_HARD_FLOAT:
+ file_mips_soft_float = 0;
+ break;
+
#ifdef OBJ_ELF
case OPTION_MABI:
if (!IS_ELF)
return 0;
}
+ mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
return 1;
}
\f
arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
- as_bad ("-march=%s is not compatible with the selected ABI",
+ as_bad (_("-march=%s is not compatible with the selected ABI"),
arch_info->name);
mips_set_architecture (arch_info);
if (mips_opts.ase_smartmips == -1)
mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
- as_warn ("%s ISA does not support SmartMIPS",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support SmartMIPS"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_dsp == -1)
mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
- as_warn ("%s ISA does not support DSP ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support DSP ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_dspr2 == -1)
{
mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
}
if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
- as_warn ("%s ISA does not support DSP R2 ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support DSP R2 ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
if (mips_opts.ase_mt == -1)
mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
- as_warn ("%s ISA does not support MT ASE",
- mips_cpu_info_from_isa (mips_opts.isa)->name);
+ as_warn (_("%s ISA does not support MT ASE"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
file_mips_isa = mips_opts.isa;
file_ase_mips16 = mips_opts.mips16;
file_ase_mt = mips_opts.ase_mt;
mips_opts.gp32 = file_mips_gp32;
mips_opts.fp32 = file_mips_fp32;
+ mips_opts.soft_float = file_mips_soft_float;
+ mips_opts.single_float = file_mips_single_float;
if (mips_flag_mdebug < 0)
{
mips_frob_file (void)
{
struct mips_hi_fixup *l;
+ bfd_reloc_code_real_type looking_for_rtype = BFD_RELOC_UNUSED;
for (l = mips_hi_fixup_list; l != NULL; l = l->next)
{
bfd_boolean matched_lo_p;
fixS **hi_pos, **lo_pos, **pos;
- assert (reloc_needs_lo_p (l->fixp->fx_r_type));
+ gas_assert (reloc_needs_lo_p (l->fixp->fx_r_type));
/* If a GOT16 relocation turns out to be against a global symbol,
there isn't supposed to be a matching LO. */
- if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
+ if (got16_reloc_p (l->fixp->fx_r_type)
&& !pic_need_relax (l->fixp->fx_addsy, l->seg))
continue;
hi_pos = NULL;
lo_pos = NULL;
matched_lo_p = FALSE;
+ looking_for_rtype = matching_lo_reloc (l->fixp->fx_r_type);
+
for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
{
if (*pos == l->fixp)
hi_pos = pos;
- if (((*pos)->fx_r_type == BFD_RELOC_LO16
- || (*pos)->fx_r_type == BFD_RELOC_MIPS16_LO16)
- && (*pos)->fx_addsy == l->fixp->fx_addsy
+ if ((*pos)->fx_r_type == looking_for_rtype
+ && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
&& (*pos)->fx_offset >= l->fixp->fx_offset
&& (lo_pos == NULL
|| (*pos)->fx_offset < (*lo_pos)->fx_offset
if (HAVE_NEWABI
&& S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
&& (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
- || fixp->fx_r_type == BFD_RELOC_HI16_S
- || fixp->fx_r_type == BFD_RELOC_LO16))
+ || hi16_reloc_p (fixp->fx_r_type)
+ || lo16_reloc_p (fixp->fx_r_type)))
return 1;
return 0;
if (! howto)
return;
- assert (fixP->fx_size == 4
+ gas_assert (fixP->fx_size == 4
|| fixP->fx_r_type == BFD_RELOC_16
|| fixP->fx_r_type == BFD_RELOC_64
|| fixP->fx_r_type == BFD_RELOC_CTOR
buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
- assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
+ gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
/* Don't treat parts of a composite relocation as done. There are two
reasons for this:
case BFD_RELOC_MIPS_CALL_HI16:
case BFD_RELOC_MIPS_CALL_LO16:
case BFD_RELOC_MIPS16_GPREL:
+ case BFD_RELOC_MIPS16_GOT16:
+ case BFD_RELOC_MIPS16_CALL16:
case BFD_RELOC_MIPS16_HI16:
case BFD_RELOC_MIPS16_HI16_S:
case BFD_RELOC_MIPS16_JMP:
return p;
}
-/* Align the current frag to a given power of two. The MIPS assembler
- also automatically adjusts any preceding label. */
+/* Align the current frag to a given power of two. If a particular
+ fill byte should be used, FILL points to an integer that contains
+ that byte, otherwise FILL is null.
+
+ The MIPS assembler also automatically adjusts any preceding
+ label. */
static void
-mips_align (int to, int fill, symbolS *label)
+mips_align (int to, int *fill, symbolS *label)
{
mips_emit_delays ();
- frag_align (to, fill, 0);
+ mips_record_mips16_mode ();
+ if (fill == NULL && subseg_text_p (now_seg))
+ frag_align_code (to, 0);
+ else
+ frag_align (to, fill ? *fill : 0, 0);
record_alignment (now_seg, to);
if (label != NULL)
{
- assert (S_GET_SEGMENT (label) == now_seg);
+ gas_assert (S_GET_SEGMENT (label) == now_seg);
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, (valueT) frag_now_fix ());
}
static void
s_align (int x ATTRIBUTE_UNUSED)
{
- int temp;
- long temp_fill;
+ int temp, fill_value, *fill_ptr;
long max_alignment = 28;
/* o Note that the assembler pulls down any immediately preceding label
if (*input_line_pointer == ',')
{
++input_line_pointer;
- temp_fill = get_absolute_expression ();
+ fill_value = get_absolute_expression ();
+ fill_ptr = &fill_value;
}
else
- temp_fill = 0;
+ fill_ptr = 0;
if (temp)
{
segment_info_type *si = seg_info (now_seg);
struct insn_label_list *l = si->label_list;
/* Auto alignment should be switched on by next section change. */
auto_align = 1;
- mips_align (temp, (int) temp_fill, l != NULL ? l->label : NULL);
+ mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
}
else
{
#endif
mips_emit_delays ();
+
switch (sec)
{
case 't':
bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
| SEC_READONLY | SEC_RELOC
| SEC_DATA));
- if (strcmp (TARGET_OS, "elf") != 0)
+ if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
}
demand_empty_rest_of_line ();
{
bfd_set_section_flags (stdoutput, seg,
SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
- if (strcmp (TARGET_OS, "elf") != 0)
+ if (strncmp (TARGET_OS, "elf", 3) != 0)
record_alignment (seg, 4);
}
demand_empty_rest_of_line ();
section_alignment = get_absolute_expression ();
else
section_alignment = 0;
+ /* FIXME: really ignore? */
+ (void) section_alignment;
section_name = xstrdup (section_name);
else if (strcmp (name, "gp=64") == 0)
{
if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
- as_warn ("%s isa does not support 64-bit registers",
+ as_warn (_("%s isa does not support 64-bit registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.gp32 = 0;
}
else if (strcmp (name, "fp=64") == 0)
{
if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
- as_warn ("%s isa does not support 64-bit floating point registers",
+ as_warn (_("%s isa does not support 64-bit floating point registers"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.fp32 = 0;
}
+ else if (strcmp (name, "softfloat") == 0)
+ mips_opts.soft_float = 1;
+ else if (strcmp (name, "hardfloat") == 0)
+ mips_opts.soft_float = 0;
+ else if (strcmp (name, "singlefloat") == 0)
+ mips_opts.single_float = 1;
+ else if (strcmp (name, "doublefloat") == 0)
+ mips_opts.single_float = 0;
else if (strcmp (name, "mips16") == 0
|| strcmp (name, "MIPS-16") == 0)
mips_opts.mips16 = 1;
else if (strcmp (name, "smartmips") == 0)
{
if (!ISA_SUPPORTS_SMARTMIPS)
- as_warn ("%s ISA does not support SmartMIPS ASE",
+ as_warn (_("%s ISA does not support SmartMIPS ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_smartmips = 1;
}
else if (strcmp (name, "dsp") == 0)
{
if (!ISA_SUPPORTS_DSP_ASE)
- as_warn ("%s ISA does not support DSP ASE",
+ as_warn (_("%s ISA does not support DSP ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_dsp = 1;
mips_opts.ase_dspr2 = 0;
else if (strcmp (name, "dspr2") == 0)
{
if (!ISA_SUPPORTS_DSPR2_ASE)
- as_warn ("%s ISA does not support DSP R2 ASE",
+ as_warn (_("%s ISA does not support DSP R2 ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_dspr2 = 1;
mips_opts.ase_dsp = 1;
else if (strcmp (name, "mt") == 0)
{
if (!ISA_SUPPORTS_MT_ASE)
- as_warn ("%s ISA does not support MT ASE",
+ as_warn (_("%s ISA does not support MT ASE"),
mips_cpu_info_from_isa (mips_opts.isa)->name);
mips_opts.ase_mt = 1;
}
{
if (S_IS_DEFINED (symbolP))
{
- as_bad ("ignoring attempt to redefine symbol %s",
+ as_bad (_("ignoring attempt to redefine symbol %s"),
S_GET_NAME (symbolP));
ignore_rest_of_line ();
return;
expression (&exp);
if (exp.X_op != O_symbol)
{
- as_bad ("bad .weakext directive");
+ as_bad (_("bad .weakext directive"));
ignore_rest_of_line ();
return;
}
However, Irix 5 may prefer that we align them at least to a 16
byte boundary. We don't bother to align the sections if we
are targeted for an embedded system. */
- if (strcmp (TARGET_OS, "elf") == 0)
+ if (strncmp (TARGET_OS, "elf", 3) == 0)
return addr;
if (align > 4)
align = 4;
const char *segname;
segname = segment_name (S_GET_SEGMENT (sym));
- assert (strcmp (segname, ".lit8") != 0
+ gas_assert (strcmp (segname, ".lit8") != 0
&& strcmp (segname, ".lit4") != 0);
change = (strcmp (segname, ".sdata") != 0
&& strcmp (segname, ".sbss") != 0
while (op->type != type)
{
++op;
- assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+ gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
}
if (op->unsp)
placed anywhere. Rather than break backwards compatibility by changing
this, it seems better not to force the issue, and instead keep the
original symbol. This will work with either linker behavior. */
- if ((fixp->fx_r_type == BFD_RELOC_LO16
- || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
+ if ((lo16_reloc_p (fixp->fx_r_type)
|| reloc_needs_lo_p (fixp->fx_r_type))
&& HAVE_IN_PLACE_ADDENDS
&& (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. */
+ if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+ return 0;
+
#ifdef OBJ_ELF
/* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
to a floating-point stub. The same is true for non-R_MIPS16_26
that we have for MIPS16 symbols. */
if (IS_ELF
&& fixp->fx_subsy == NULL
- && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+ && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
|| *symbol_get_tc (fixp->fx_addsy)))
return 0;
#endif
if (fixp->fx_pcrel)
{
- assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
+ gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
/* At this point, fx_addnumber is "symbol offset - pcrel address".
Relocations want only the symbol offset. */
/* bc[0-3][tf]l? and bc1any[24][ft] instructions can
have the condition reversed by tweaking a single
bit, and their opcodes all have 0x4???????. */
- assert ((insn & 0xf1000000) == 0x41000000);
+ gas_assert ((insn & 0xf1000000) == 0x41000000);
insn ^= 0x00010000;
break;
case 0:
/* bltz 0x04000000 bgez 0x04010000
bltzal 0x04100000 bgezal 0x04110000 */
- assert ((insn & 0xfc0e0000) == 0x04000000);
+ gas_assert ((insn & 0xfc0e0000) == 0x04000000);
insn ^= 0x00010000;
break;
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
{
/* Clear the and-link bit. */
- assert ((insn & 0xfc1c0000) == 0x04100000);
+ gas_assert ((insn & 0xfc1c0000) == 0x04100000);
/* bltzal 0x04100000 bgezal 0x04110000
bltzall 0x04120000 bgezall 0x04130000 */
}
}
- assert (buf == (bfd_byte *)fragp->fr_literal
+ gas_assert (buf == (bfd_byte *)fragp->fr_literal
+ fragp->fr_fix + fragp->fr_var);
fragp->fr_fix += fragp->fr_var;
{
const char *msg = macro_warning (fragp->fr_subtype);
if (msg != 0)
- as_warn_where (fragp->fr_file, fragp->fr_line, msg);
+ as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
}
/* Go through all the fixups for the first sequence. Disable them
count = bfd_get_symcount (stdoutput);
for (i = 0; i < count; i++, syms++)
{
- if (elf_symbol (*syms)->internal_elf_sym.st_other == STO_MIPS16
+ if (ELF_ST_IS_MIPS16 (elf_symbol (*syms)->internal_elf_sym.st_other)
&& ((*syms)->value & 1) != 0)
{
(*syms)->value &= ~1;
static procS *cur_proc_ptr;
static int numprocs;
-/* Fill in an rs_align_code fragment. */
+/* Implement NOP_OPCODE. We encode a MIPS16 nop as "1" and a normal
+ nop as "0". */
+
+char
+mips_nop_opcode (void)
+{
+ return seg_info (now_seg)->tc_segment_info_data.mips16;
+}
+
+/* Fill in an rs_align_code fragment. This only needs to do something
+ for MIPS16 code, where 0 is not a nop. */
void
mips_handle_align (fragS *fragp)
{
+ char *p;
+ int bytes, size, excess;
+ valueT opcode;
+
if (fragp->fr_type != rs_align_code)
return;
- if (mips_opts.mips16)
+ p = fragp->fr_literal + fragp->fr_fix;
+ if (*p)
{
- static const unsigned char be_nop[] = { 0x65, 0x00 };
- static const unsigned char le_nop[] = { 0x00, 0x65 };
-
- int bytes;
- char *p;
-
- bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
- p = fragp->fr_literal + fragp->fr_fix;
-
- if (bytes & 1)
- {
- *p++ = 0;
- fragp->fr_fix++;
- }
+ opcode = mips16_nop_insn.insn_opcode;
+ size = 2;
+ }
+ else
+ {
+ opcode = nop_insn.insn_opcode;
+ size = 4;
+ }
- memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
- fragp->fr_var = 2;
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ excess = bytes % size;
+ if (excess != 0)
+ {
+ /* If we're not inserting a whole number of instructions,
+ pad the end of the fixed part of the frag with zeros. */
+ memset (p, 0, excess);
+ p += excess;
+ fragp->fr_fix += excess;
}
- /* For mips32, a nop is a zero, which we trivially get by doing nothing. */
+ md_number_to_chars (p, opcode, size);
+ fragp->fr_var = size;
}
static void
if (p != NULL)
{
- assert (S_GET_NAME (p));
+ gas_assert (S_GET_NAME (p));
if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
as_warn (_(".end symbol does not match .ent symbol."));
{
segT saved_seg = now_seg;
subsegT saved_subseg = now_subseg;
- valueT dot;
expressionS exp;
char *fragp;
- dot = frag_now_fix ();
-
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
- assert (pdr_seg);
+ gas_assert (pdr_seg);
subseg_set (pdr_seg, 0);
/* Write the symbol. */
cur_proc_ptr->func_sym = symbolP;
- symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
++numprocs;
if (debug_type == DEBUG_STABS)
S_GET_NAME (symbolP));
}
+ symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
demand_empty_rest_of_line ();
}
{ "r4600", 0, ISA_MIPS3, CPU_R4600 },
{ "orion", 0, ISA_MIPS3, CPU_R4600 },
{ "r4650", 0, ISA_MIPS3, CPU_R4650 },
+ /* ST Microelectronics Loongson 2E and 2F cores */
+ { "loongson2e", 0, ISA_MIPS3, CPU_LOONGSON_2E },
+ { "loongson2f", 0, ISA_MIPS3, CPU_LOONGSON_2F },
/* MIPS IV */
{ "r8000", 0, ISA_MIPS4, CPU_R8000 },
{ "r10000", 0, ISA_MIPS4, CPU_R10000 },
{ "r12000", 0, ISA_MIPS4, CPU_R12000 },
+ { "r14000", 0, ISA_MIPS4, CPU_R14000 },
+ { "r16000", 0, ISA_MIPS4, CPU_R16000 },
{ "vr5000", 0, ISA_MIPS4, CPU_R5000 },
{ "vr5400", 0, ISA_MIPS4, CPU_VR5400 },
{ "vr5500", 0, ISA_MIPS4, CPU_VR5500 },
ISA_MIPS32R2, CPU_MIPS32R2 },
{ "74kx", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
ISA_MIPS32R2, CPU_MIPS32R2 },
+ /* 1004K cores are multiprocessor versions of the 34K. */
+ { "1004kc", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf2_1", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
+ { "1004kf1_1", MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+ ISA_MIPS32R2, CPU_MIPS32R2 },
/* MIPS 64 */
{ "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
{ "20kc", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
{ "25kf", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 },
- /* MIPS 64 Release 2 */
-
/* Broadcom SB-1 CPU core */
{ "sb1", MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
ISA_MIPS64, CPU_SB1 },
{ "sb1a", MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
ISA_MIPS64, CPU_SB1 },
+ /* MIPS 64 Release 2 */
+
+ /* Cavium Networks Octeon CPU core */
+ { "octeon", 0, ISA_MIPS64R2, CPU_OCTEON },
+
+ /* RMI Xlr */
+ { "xlr", 0, ISA_MIPS64, CPU_XLR },
+
/* End marker */
{ NULL, 0, 0, 0 }
};
if (mips_matching_cpu_name_p (p->name, cpu_string))
return p;
- as_bad ("Bad value (%s) for %s", cpu_string, option);
+ as_bad (_("Bad value (%s) for %s"), cpu_string, option);
return 0;
}
-mmt generate MT instructions\n\
-mno-mt do not generate MT instructions\n"));
fprintf (stream, _("\
+-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
-mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
+-mfix-24k insert a nop after ERET and DERET instructions\n\
-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\
---[no-]construct-floats [dis]allow floating point values to be constructed\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, _("\
+-mhard-float allow floating-point instructions\n\
+-msoft-float do not allow floating-point instructions\n\
+-msingle-float only allow 32-bit floating-point operations\n\
+-mdouble-float allow 32-bit and 64-bit floating-point operations\n\
+--[no-]construct-floats [dis]allow floating point values to be constructed\n"
+ ));
#ifdef OBJ_ELF
fprintf (stream, _("\
-KPIC, -call_shared generate SVR4 position independent code\n\
+-call_nonpic generate non-PIC code that can operate with DSOs\n\
-mvxworks-pic generate VxWorks position independent code\n\
--non_shared do not generate position independent code\n\
+-non_shared do not generate code that can operate with DSOs\n\
-xgot assume a 32 bit GOT\n\
-mpdr, -mno-pdr enable/disable creation of .pdr sections\n\
-mshared, -mno-shared disable/enable .cpload optimization for\n\
#endif
}
+#ifdef TE_IRIX
enum dwarf2_format
-mips_dwarf2_format (void)
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
{
if (HAVE_64BIT_SYMBOLS)
- {
-#ifdef TE_IRIX
- return dwarf2_format_64bit_irix;
-#else
- return dwarf2_format_64bit;
-#endif
- }
+ return dwarf2_format_64bit_irix;
else
return dwarf2_format_32bit;
}
+#endif
int
mips_dwarf2_addr_size (void)
{
- if (HAVE_64BIT_SYMBOLS)
+ if (HAVE_64BIT_OBJECTS)
return 8;
else
return 4;