#include "opcode/mips.h"
#include "itbl-ops.h"
+#include "dwarf2dbg.h"
#ifdef DEBUG
#define DBG(x) printf x
#define ECOFF_DEBUGGING 0
#endif
+int mips_flag_mdebug = -1;
+
#include "ecoff.h"
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
static char *mips_regmask_frag;
#endif
+#define ZERO 0
#define AT 1
#define TREG 24
#define PIC_CALL_REG 25
};
/* MIPS ABI we are using for this output file. */
-static enum mips_abi_level file_mips_abi = NO_ABI;
+static enum mips_abi_level mips_abi = NO_ABI;
/* This is the set of options which may be modified by the .set
pseudo-op. We use a struct so that .set push and .set pop are more
is passed but can changed if the assembler code uses .set mipsN. */
int gp32;
int fp32;
- /* The ABI currently in use. This is changed by .set mipsN to loosen
- restrictions and doesn't affect the whole file. */
- enum mips_abi_level abi;
};
/* True if -mgp32 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 mips16 field to
+ that we must set the isa field to ISA_UNKNOWN and the ASE fields to
-1 to indicate that they have not been initialized. */
static struct mips_set_options mips_opts =
{
- ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, NO_ABI
+ ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0
};
/* These variables are filled in with the masks of registers used.
/* MIPS ISA we are using for this output file. */
static int file_mips_isa = ISA_UNKNOWN;
+/* True if -mips16 was passed or implied by arguments passed on the
+ command line (e.g., by -march). */
+static int file_ase_mips16;
+
/* True if -mips3d was passed or implied by arguments passed on the
command line (e.g., by -march). */
static int file_ase_mips3d;
command line (e.g., by -march). */
static int file_ase_mdmx;
-/* The argument of the -mcpu= flag. Historical for code generation. */
-static int mips_cpu = CPU_UNKNOWN;
-
/* The argument of the -march= flag. The architecture we are assembling. */
static int mips_arch = CPU_UNKNOWN;
+static const char *mips_arch_string;
+static const struct mips_cpu_info *mips_arch_info;
/* The argument of the -mtune= flag. The architecture for which we
are optimizing. */
static int mips_tune = CPU_UNKNOWN;
+static const char *mips_tune_string;
+static const struct mips_cpu_info *mips_tune_info;
-/* Whether we should mark the file EABI64 or EABI32. */
-static int mips_eabi64 = 0;
-
-/* If they asked for mips1 or mips2 and a cpu that is
- mips3 or greater, then mark the object file 32BITMODE. */
+/* True when generating 32-bit code for a 64-bit processor. */
static int mips_32bitmode = 0;
/* Some ISA's have delay slots for instructions which read or write
|| (ISA) == ISA_MIPS3 \
)
+/* True if the given ABI requires 32-bit registers. */
+#define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI)
+
+/* Likewise 64-bit registers. */
+#define ABI_NEEDS_64BIT_REGS(ABI) \
+ ((ABI) == N32_ABI \
+ || (ABI) == N64_ABI \
+ || (ABI) == O64_ABI)
+
/* Return true if ISA supports 64 bit gp register instructions. */
#define ISA_HAS_64BIT_REGS(ISA) ( \
(ISA) == ISA_MIPS3 \
)
#define HAVE_32BIT_GPRS \
- (mips_opts.gp32 \
- || mips_opts.abi == O32_ABI \
- || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+ (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
#define HAVE_32BIT_FPRS \
- (mips_opts.fp32 \
- || mips_opts.abi == O32_ABI \
- || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+ (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
-#define HAVE_NEWABI (mips_opts.abi == N32_ABI || mips_opts.abi == N64_ABI)
+#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
-#define HAVE_64BIT_OBJECTS (mips_opts.abi == N64_ABI)
+#define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
/* We can only have 64bit addresses if the object file format
supports it. */
#define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES)
+/* Return true if the given CPU supports the MIPS16 ASE. */
+#define CPU_HAS_MIPS16(cpu) \
+ (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0)
+
/* Return true if the given CPU supports the MIPS3D ASE. */
#define CPU_HAS_MIPS3D(cpu) ((cpu) == CPU_SB1 \
)
/* Return true if the given CPU supports the MDMX ASE. */
-#define CPU_HAS_MDMX(cpu) (0 \
+#define CPU_HAS_MDMX(cpu) (false \
)
/* Whether the processor uses hardware interlocks to protect
/* Do not generate PIC code. */
NO_PIC,
- /* Generate PIC code as in Irix 4. This is not implemented, and I'm
- not sure what it is supposed to do. */
- IRIX4_PIC,
-
/* Generate PIC code as in the SVR4 MIPS ABI. */
SVR4_PIC,
#ifdef OBJ_ELF
static int support_64bit_objects PARAMS((void));
#endif
+static void mips_set_option_string PARAMS ((const char **, const char *));
static symbolS *get_symbol PARAMS ((void));
static void mips_align PARAMS ((int to, int fill, symbolS *label));
static void s_align PARAMS ((int));
static void s_mips_mask PARAMS ((int));
static void s_mips_stab PARAMS ((int));
static void s_mips_weakext PARAMS ((int));
-static void s_file PARAMS ((int));
+static void s_mips_file PARAMS ((int));
+static void s_mips_loc PARAMS ((int));
static int mips16_extended_frag PARAMS ((fragS *, asection *, long));
-static const char *mips_isa_to_str PARAMS ((int));
-static const char *mips_cpu_to_str PARAMS ((int));
static int validate_mips_insn PARAMS ((const struct mips_opcode *));
-static void show PARAMS ((FILE *, char *, int *, int *));
+static void show PARAMS ((FILE *, const char *, int *, int *));
#ifdef OBJ_ELF
static int mips_need_elf_addend_fixup PARAMS ((fixS *));
#endif
int cpu; /* CPU number (default CPU if ISA). */
};
-static const struct mips_cpu_info *mips_cpu_info_from_name PARAMS ((const char *));
+static void mips_set_architecture PARAMS ((const struct mips_cpu_info *));
+static void mips_set_tune PARAMS ((const struct mips_cpu_info *));
+static boolean mips_strict_matching_cpu_name_p PARAMS ((const char *,
+ const char *));
+static boolean mips_matching_cpu_name_p PARAMS ((const char *, const char *));
+static const struct mips_cpu_info *mips_parse_cpu PARAMS ((const char *,
+ const char *));
static const struct mips_cpu_info *mips_cpu_info_from_isa PARAMS ((int));
-static const struct mips_cpu_info *mips_cpu_info_from_cpu PARAMS ((int));
\f
/* Pseudo-op table.
{"text", s_change_sec, 't'},
{"word", s_cons, 2},
-#ifdef MIPS_STABS_ELF
{ "extern", ecoff_directive_extern, 0},
-#endif
{ NULL, NULL, 0 },
};
{"end", s_mips_end, 0},
{"endb", s_ignore, 0},
{"ent", s_mips_ent, 0},
- {"file", s_file, 0},
+ {"file", s_mips_file, 0},
{"fmask", s_mips_mask, 'F'},
{"frame", s_mips_frame, 0},
- {"loc", s_ignore, 0},
+ {"loc", s_mips_loc, 0},
{"mask", s_mips_mask, 'R'},
{"verstamp", s_ignore, 0},
{ NULL, NULL, 0 },
static boolean mips16_small, mips16_ext;
-#ifdef MIPS_STABS_ELF
-/* The pdr segment for per procedure frame/regmask info */
+/* The pdr segment for per procedure frame/regmask info. Not used for
+ ECOFF debugging. */
static segT pdr_seg;
-#endif
-
-static const char *
-mips_isa_to_str (isa)
- int isa;
-{
- const struct mips_cpu_info *ci;
- static char s[20];
-
- ci = mips_cpu_info_from_isa (isa);
- if (ci != NULL)
- return (ci->name);
-
- sprintf (s, "ISA#%d", isa);
- return s;
-}
-
-static const char *
-mips_cpu_to_str (cpu)
- int cpu;
-{
- const struct mips_cpu_info *ci;
- static char s[16];
-
- ci = mips_cpu_info_from_cpu (cpu);
- if (ci != NULL)
- return (ci->name);
-
- sprintf (s, "CPU#%d", cpu);
- return s;
-}
/* The default target format to use. */
return "pe-mips";
case bfd_target_elf_flavour:
#ifdef TE_TMIPS
- /* This is traditional mips */
+ /* This is traditional mips. */
return (target_big_endian
- ? (HAVE_64BIT_OBJECTS ? "elf64-tradbigmips"
- : "elf32-tradbigmips")
- : (HAVE_64BIT_OBJECTS ? "elf64-tradlittlemips"
- : "elf32-tradlittlemips"));
+ ? (HAVE_64BIT_OBJECTS
+ ? "elf64-tradbigmips"
+ : (HAVE_NEWABI
+ ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
+ : (HAVE_64BIT_OBJECTS
+ ? "elf64-tradlittlemips"
+ : (HAVE_NEWABI
+ ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
#else
return (target_big_endian
- ? (HAVE_64BIT_OBJECTS ? "elf64-bigmips" : "elf32-bigmips")
- : (HAVE_64BIT_OBJECTS ? "elf64-littlemips"
- : "elf32-littlemips"));
+ ? (HAVE_64BIT_OBJECTS
+ ? "elf64-bigmips"
+ : (HAVE_NEWABI
+ ? "elf32-nbigmips" : "elf32-bigmips"))
+ : (HAVE_64BIT_OBJECTS
+ ? "elf64-littlemips"
+ : (HAVE_NEWABI
+ ? "elf32-nlittlemips" : "elf32-littlemips")));
#endif
default:
abort ();
{
register const char *retval = NULL;
int i = 0;
- const char *cpu;
- char *a = NULL;
int broken = 0;
- int mips_isa_from_cpu;
- int target_cpu_had_mips16 = 0;
- const struct mips_cpu_info *ci;
-
- /* GP relative stuff not working for PE */
- if (strncmp (TARGET_OS, "pe", 2) == 0
- && g_switch_value != 0)
- {
- if (g_switch_seen)
- as_bad (_("-G not supported in this configuration."));
- g_switch_value = 0;
- }
-
- cpu = TARGET_CPU;
- if (strcmp (cpu + (sizeof TARGET_CPU) - 3, "el") == 0)
- {
- a = xmalloc (sizeof TARGET_CPU);
- strcpy (a, TARGET_CPU);
- a[(sizeof TARGET_CPU) - 3] = '\0';
- cpu = a;
- }
-
- if (strncmp (cpu, "mips16", sizeof "mips16" - 1) == 0)
- {
- target_cpu_had_mips16 = 1;
- cpu += sizeof "mips16" - 1;
- }
-
- if (mips_opts.mips16 < 0)
- mips_opts.mips16 = target_cpu_had_mips16;
-
- /* Backward compatibility for historic -mcpu= option. Check for
- incompatible options, warn if -mcpu is used. */
- if (mips_cpu != CPU_UNKNOWN
- && mips_arch != CPU_UNKNOWN
- && mips_cpu != mips_arch)
- {
- as_fatal (_("The -mcpu option can't be used together with -march. "
- "Use -mtune instead of -mcpu."));
- }
-
- if (mips_cpu != CPU_UNKNOWN
- && mips_tune != CPU_UNKNOWN
- && mips_cpu != mips_tune)
- {
- as_fatal (_("The -mcpu option can't be used together with -mtune. "
- "Use -march instead of -mcpu."));
- }
-
-#if 1
- /* For backward compatibility, let -mipsN set various defaults. */
- /* This code should go away, to be replaced with something rather more
- draconian. Until GCC 3.1 has been released for some reasonable
- amount of time, however, we need to support this. */
- if (mips_opts.isa != ISA_UNKNOWN)
- {
- /* Translate -mipsN to the appropriate settings of file_mips_gp32
- and file_mips_fp32. Tag binaries as using the mipsN ISA. */
- if (file_mips_gp32 < 0)
- {
- if (ISA_HAS_64BIT_REGS (mips_opts.isa))
- file_mips_gp32 = 0;
- else
- file_mips_gp32 = 1;
- }
- if (file_mips_fp32 < 0)
- {
- if (ISA_HAS_64BIT_REGS (mips_opts.isa))
- file_mips_fp32 = 0;
- else
- file_mips_fp32 = 1;
- }
-
- ci = mips_cpu_info_from_isa (mips_opts.isa);
- assert (ci != NULL);
- /* -mipsN has higher priority than -mcpu but lower than -march. */
- if (mips_arch == CPU_UNKNOWN)
- mips_arch = ci->cpu;
-
- /* Default mips_abi. */
- if (mips_opts.abi == NO_ABI)
- {
- if (mips_opts.isa == ISA_MIPS1 || mips_opts.isa == ISA_MIPS2)
- mips_opts.abi = O32_ABI;
- else if (mips_opts.isa == ISA_MIPS3 || mips_opts.isa == ISA_MIPS4)
- mips_opts.abi = O64_ABI;
- }
- }
-
- if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
- {
- ci = mips_cpu_info_from_cpu (mips_cpu);
- assert (ci != NULL);
- mips_arch = ci->cpu;
- as_warn (_("The -mcpu option is deprecated. Please use -march and "
- "-mtune instead."));
- }
-
- /* Set tune from -mcpu, not from -mipsN. */
- if (mips_tune == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
- {
- ci = mips_cpu_info_from_cpu (mips_cpu);
- assert (ci != NULL);
- mips_tune = ci->cpu;
- }
-
- /* At this point, mips_arch will either be CPU_UNKNOWN if no ARCH was
- specified on the command line, or some other value if one was.
- Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
- the command line, or will be set otherwise if one was. */
-
- if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
- /* Handled above. */;
-#else
- if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
- {
- ci = mips_cpu_info_from_cpu (mips_cpu);
- assert (ci != NULL);
- mips_arch = ci->cpu;
- as_warn (_("The -mcpu option is deprecated. Please use -march and "
- "-mtune instead."));
- }
-
- /* At this point, mips_arch will either be CPU_UNKNOWN if no ARCH was
- specified on the command line, or some other value if one was.
- Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
- the command line, or will be set otherwise if one was. */
-
- if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
- {
- /* We have to check if the isa is the default isa of arch. Otherwise
- we'll get invalid object file headers. */
- ci = mips_cpu_info_from_cpu (mips_arch);
- assert (ci != NULL);
- if (mips_opts.isa != ci->isa)
- {
- /* This really should be an error instead of a warning, but old
- compilers only have -mcpu which sets both arch and tune. For
- now, we discard arch and preserve tune. */
- as_warn (_("The -march option is incompatible to -mipsN and "
- "therefore ignored."));
- if (mips_tune == CPU_UNKNOWN)
- mips_tune = mips_arch;
- ci = mips_cpu_info_from_isa (mips_opts.isa);
- assert (ci != NULL);
- mips_arch = ci->cpu;
- }
- }
-#endif
- else if (mips_arch != CPU_UNKNOWN && mips_opts.isa == ISA_UNKNOWN)
- {
- /* We have ARCH, we need ISA. */
- ci = mips_cpu_info_from_cpu (mips_arch);
- assert (ci != NULL);
- mips_opts.isa = ci->isa;
- }
- else if (mips_arch == CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
- {
- /* We have ISA, we need default ARCH. */
- ci = mips_cpu_info_from_isa (mips_opts.isa);
- assert (ci != NULL);
- mips_arch = ci->cpu;
- }
- else
- {
- /* We need to set both ISA and ARCH from target cpu. */
- ci = mips_cpu_info_from_name (cpu);
- if (ci == NULL)
- ci = mips_cpu_info_from_cpu (CPU_R3000);
- assert (ci != NULL);
- mips_opts.isa = ci->isa;
- mips_arch = ci->cpu;
- }
-
- if (mips_tune == CPU_UNKNOWN)
- mips_tune = mips_arch;
-
- ci = mips_cpu_info_from_cpu (mips_arch);
- assert (ci != NULL);
- mips_isa_from_cpu = ci->isa;
-
- /* End of TARGET_CPU processing, get rid of malloced memory
- if necessary. */
- cpu = NULL;
- if (a != NULL)
- {
- free (a);
- a = NULL;
- }
-
- if (mips_opts.isa == ISA_MIPS1 && mips_trap)
- as_bad (_("trap exception not supported at ISA 1"));
-
- /* Set the EABI kind based on the ISA before the user gets
- to change the ISA with directives. This isn't really
- the best, but then neither is basing the abi on the isa. */
- if (ISA_HAS_64BIT_REGS (mips_opts.isa)
- && mips_opts.abi == EABI_ABI)
- mips_eabi64 = 1;
-
- /* If they asked for mips1 or mips2 and a cpu that is
- mips3 or greater, then mark the object file 32BITMODE. */
- if (mips_isa_from_cpu != ISA_UNKNOWN
- && ! ISA_HAS_64BIT_REGS (mips_opts.isa)
- && ISA_HAS_64BIT_REGS (mips_isa_from_cpu))
- mips_32bitmode = 1;
-
- /* If the selected architecture includes support for ASEs, enable
- generation of code for them. */
- if (mips_opts.ase_mips3d == -1 && CPU_HAS_MIPS3D (mips_arch))
- mips_opts.ase_mips3d = 1;
- if (mips_opts.ase_mdmx == -1 && CPU_HAS_MDMX (mips_arch))
- mips_opts.ase_mdmx = 1;
if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_arch))
as_warn (_("Could not set architecture and machine"));
- if (file_mips_gp32 < 0)
- file_mips_gp32 = 0;
- if (file_mips_fp32 < 0)
- file_mips_fp32 = 0;
-
- file_mips_isa = mips_opts.isa;
- file_mips_abi = mips_opts.abi;
- file_ase_mips3d = mips_opts.ase_mips3d;
- file_ase_mdmx = mips_opts.ase_mdmx;
- mips_opts.gp32 = file_mips_gp32;
- mips_opts.fp32 = file_mips_fp32;
-
- if (HAVE_NEWABI)
- mips_big_got = 1;
-
op_hash = hash_new ();
for (i = 0; i < NUMOPCODES;)
&zero_address_frag));
symbol_table_insert (symbol_new ("$kt1", reg_section, KT1,
&zero_address_frag));
+ symbol_table_insert (symbol_new ("$zero", reg_section, ZERO,
+ &zero_address_frag));
symbol_table_insert (symbol_new ("$pc", reg_section, -1,
&zero_address_frag));
if (strcmp (TARGET_OS, "elf") != 0)
flags |= SEC_ALLOC | SEC_LOAD;
- if (file_mips_abi != N64_ABI)
+ if (mips_abi != N64_ABI)
{
sec = subseg_new (".reginfo", (subsegT) 0);
SEC_HAS_CONTENTS | SEC_READONLY);
(void) bfd_set_section_alignment (stdoutput, sec, 2);
}
-
-#ifdef MIPS_STABS_ELF
- pdr_seg = subseg_new (".pdr", (subsegT) 0);
- (void) bfd_set_section_flags (stdoutput, pdr_seg,
- SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
- (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+#ifdef OBJ_ELF
+ else if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ {
+ pdr_seg = subseg_new (".pdr", (subsegT) 0);
+ (void) bfd_set_section_flags (stdoutput, pdr_seg,
+ SEC_READONLY | SEC_RELOC
+ | SEC_DEBUGGING);
+ (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+ }
#endif
subseg_set (seg, subseg);
class = MIPS_GR_REG;
}
- /* Don't report on general register 0, since it never changes. */
- if (class == MIPS_GR_REG && reg == 0)
+ /* Don't report on general register ZERO, since it never changes. */
+ if (class == MIPS_GR_REG && reg == ZERO)
return 0;
if (class == MIPS_FP_REG)
}
if (! mips_opts.mips16)
- md_number_to_chars (f, ip->insn_opcode, 4);
+ {
+ md_number_to_chars (f, ip->insn_opcode, 4);
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (4);
+#endif
+ }
else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
{
md_number_to_chars (f, ip->insn_opcode >> 16, 2);
md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (4);
+#endif
}
else
{
f += 2;
}
md_number_to_chars (f, ip->insn_opcode, 2);
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (ip->use_extend ? 4 : 2);
+#endif
}
/* Update the register mask information. */
MDMX or MIPS-3D instructions. */
if (strcmp (fmt, insn.insn_mo->args) == 0
&& insn.insn_mo->pinfo != INSN_MACRO
- && OPCODE_IS_MEMBER (insn.insn_mo, mips_opts.isa, mips_arch)
+ && OPCODE_IS_MEMBER (insn.insn_mo,
+ (mips_opts.isa
+ | (mips_opts.mips16 ? INSN_MIPS16 : 0)),
+ mips_arch)
&& (mips_arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
break;
int icnt;
expressionS *ep;
{
+ char *f;
+
if (HAVE_NEWABI)
- frag_more (0);
+ {
+ frag_grow (4);
+ f = frag_more (0);
+ }
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
RA, PIC_CALL_REG);
if (HAVE_NEWABI)
- fix_new_exp (frag_now, 0, 0, ep, false, BFD_RELOC_MIPS_JALR);
+ fix_new_exp (frag_now, f - frag_now->fr_literal,
+ 0, ep, false, BFD_RELOC_MIPS_JALR);
}
/*
struct mips_cl_insn insn;
bfd_reloc_code_real_type r[3]
= {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
- CONST char *name = "lui";
- CONST char *fmt = "t,u";
+ const char *name = "lui";
+ const char *fmt = "t,u";
assert (! mips_opts.mips16);
daddiu $reg,<sym> (BFD_RELOC_MIPS_HIGHER)
daddiu $at,<sym> (BFD_RELOC_LO16)
dsll32 $reg,0
- dadd $reg,$reg,$at
+ daddu $reg,$reg,$at
If $at is already in use, we use an path which is suboptimal
on superscalar processors.
/* We don't do GP optimization for now because RELAX_ENCODE can't
hold the data for such large chunks. */
- if (*used_at == 0)
+ if (*used_at == 0 && ! mips_opts.noat)
{
macro_build (p, counter, ep, "lui", "t,u",
reg, (int) BFD_RELOC_MIPS_HIGHEST);
AT, AT, (int) BFD_RELOC_LO16);
macro_build (p, counter, (expressionS *) NULL, "dsll32",
"d,w,<", reg, reg, 0);
- macro_build (p, counter, (expressionS *) NULL, "dadd",
+ macro_build (p, counter, (expressionS *) NULL, "daddu",
"d,v,t", reg, reg, AT);
*used_at = 1;
}
as_warn (_("Divide by zero."));
if (mips_trap)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
- "s,t", 0, 0);
+ "s,t,q", 0, 0, 7);
else
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
"c", 7);
if (mips_trap)
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
- "s,t", treg, 0);
+ "s,t,q", treg, 0, 7);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
}
if (mips_trap)
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
- "s,t", sreg, AT);
+ "s,t,q", sreg, AT, 6);
/* We want to close the noreorder block as soon as possible, so
that later insns are available for delay slot filling. */
--mips_opts.noreorder;
as_warn (_("Divide by zero."));
if (mips_trap)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
- "s,t", 0, 0);
+ "s,t,q", 0, 0, 7);
else
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
"c", 7);
if (mips_trap)
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
- "s,t", treg, 0);
+ "s,t,q", treg, 0, 7);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "z,s,t",
sreg, treg);
/* We want to close the noreorder block as soon as possible, so
if (! dbl && HAVE_64BIT_OBJECTS)
as_warn (_("la used to load 64-bit address"));
+ if (offset_expr.X_op == O_constant
+ && offset_expr.X_add_number >= -0x8000
+ && offset_expr.X_add_number < 0x8000)
+ {
+ macro_build ((char *) NULL, &icnt, &offset_expr,
+ (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
+ "t,r,j", treg, sreg, (int) BFD_RELOC_LO16);
+ return;
+ }
+
if (treg == breg)
{
tempreg = AT;
daddiu $tempreg,<sym> (BFD_RELOC_MIPS_HIGHER)
daddiu $at,<sym> (BFD_RELOC_LO16)
dsll32 $tempreg,0
- dadd $tempreg,$tempreg,$at
+ daddu $tempreg,$tempreg,$at
If $at is already in use, we use an path which is suboptimal
on superscalar processors.
/* We don't do GP optimization for now because RELAX_ENCODE can't
hold the data for such large chunks. */
- if (used_at == 0)
+ if (used_at == 0 && ! mips_opts.noat)
{
macro_build (p, &icnt, &offset_expr, "lui", "t,u",
tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
AT, AT, (int) BFD_RELOC_LO16);
macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
"d,w,<", tempreg, tempreg, 0);
- macro_build (p, &icnt, (expressionS *) NULL, "dadd", "d,v,t",
- tempreg, tempreg, AT);
+ macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+ "d,v,t", tempreg, tempreg, AT);
used_at = 1;
}
else
If we have 64-bit addresses, as an optimization, for
addresses which are 32-bit constants (e.g. kseg0/kseg1
addresses) we fall back to the 32-bit address generation
- mechanism since it is more efficient. This code should
+ mechanism since it is more efficient. Note that due to
+ the signed offset used by memory operations, the 32-bit
+ range is shifted down by 32768 here. This code should
probably attempt to generate 64-bit constants more
efficiently in general.
*/
if (HAVE_64BIT_ADDRESSES
&& !(offset_expr.X_op == O_constant
- && IS_SEXT_32BIT_NUM (offset_expr.X_add_number)))
+ && IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
{
p = NULL;
/* We don't do GP optimization for now because RELAX_ENCODE can't
hold the data for such large chunks. */
- if (used_at == 0)
+ if (used_at == 0 && ! mips_opts.noat)
{
macro_build (p, &icnt, &offset_expr, "lui", "t,u",
tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mfhi", "d",
AT);
if (mips_trap)
- macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
- dreg, AT);
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne",
+ "s,t,q", dreg, AT, 6);
else
{
expr1.X_add_number = 8;
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
dreg);
if (mips_trap)
- macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
- AT, 0);
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne",
+ "s,t,q", AT, 0, 6);
else
{
expr1.X_add_number = 8;
if (OPCODE_IS_MEMBER (insn,
(mips_opts.isa
+ | (mips_opts.mips16 ? INSN_MIPS16 : 0)
| (mips_opts.ase_mdmx ? INSN_MDMX : 0)
| (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)),
mips_arch))
if (!insn_error)
{
static char buf[100];
- sprintf (buf,
- _("opcode not supported on this processor: %s (%s)"),
- mips_cpu_to_str (mips_arch),
- mips_isa_to_str (mips_opts.isa));
-
+ if (mips_arch_info->is_isa)
+ sprintf (buf,
+ _("opcode not supported at this ISA level (%s)"),
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ else
+ sprintf (buf,
+ _("opcode not supported on this processor: %s (%s)"),
+ mips_arch_info->name,
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
insn_error = buf;
}
if (save_c)
s += 4;
regno = KT1;
}
+ else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+ {
+ s += 5;
+ regno = ZERO;
+ }
else if (itbl_have_entries)
{
char *p, *n;
{
if (c != S_EX_LO)
{
- if (imm_expr.X_op == O_constant)
- imm_expr.X_add_number =
- (imm_expr.X_add_number >> 16) & 0xffff;
+ if (c == S_EX_HI)
+ {
+ *imm_reloc = BFD_RELOC_HI16_S;
+ imm_unmatched_hi = true;
+ }
#ifdef OBJ_ELF
else if (c == S_EX_HIGHEST)
*imm_reloc = BFD_RELOC_MIPS_HIGHEST;
}
}
#endif
- else if (c == S_EX_HI)
- {
- *imm_reloc = BFD_RELOC_HI16_S;
- imm_unmatched_hi = true;
- }
else
*imm_reloc = BFD_RELOC_HI16;
}
{
if (c != S_EX_LO)
{
- if (imm_expr.X_op == O_constant)
- imm_expr.X_add_number =
- (imm_expr.X_add_number >> 16) & 0xffff;
- else if (c == S_EX_HI)
+ if (c == S_EX_HI)
{
*imm_reloc = BFD_RELOC_HI16_S;
imm_unmatched_hi = true;
else if (imm_expr.X_op == O_constant)
imm_expr.X_add_number &= 0xffff;
}
- if (imm_expr.X_op == O_constant
- && (imm_expr.X_add_number < 0
- || imm_expr.X_add_number >= 0x10000))
+ else if (imm_expr.X_op == O_constant
+ && (imm_expr.X_add_number < 0
+ || imm_expr.X_add_number >= 0x10000))
as_bad (_("lui expression not in range 0..65535"));
s = expr_end;
continue;
s += 4;
regno = KT1;
}
+ else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+ {
+ s += 5;
+ regno = ZERO;
+ }
else
break;
}
}
#endif /* OBJ_ELF */
-CONST char *md_shortopts = "nO::g::G:";
+const char *md_shortopts = "nO::g::G:";
struct option md_longopts[] =
{
{"march", required_argument, NULL, OPTION_MARCH},
#define OPTION_MTUNE (OPTION_MD_BASE + 22)
{"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_MCPU (OPTION_MD_BASE + 23)
- {"mcpu", required_argument, NULL, OPTION_MCPU},
+#define OPTION_FP64 (OPTION_MD_BASE + 23)
+ {"mfp64", no_argument, NULL, OPTION_FP64},
#define OPTION_M4650 (OPTION_MD_BASE + 24)
{"m4650", no_argument, NULL, OPTION_M4650},
#define OPTION_NO_M4650 (OPTION_MD_BASE + 25)
{"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},
#endif /* OBJ_ELF */
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
+/* Set STRING_PTR (either &mips_arch_string or &mips_tune_string) to
+ NEW_VALUE. Warn if another value was already specified. Note:
+ we have to defer parsing the -march and -mtune arguments in order
+ to handle 'from-abi' correctly, since the ABI might be specified
+ in a later argument. */
+
+static void
+mips_set_option_string (string_ptr, new_value)
+ const char **string_ptr, *new_value;
+{
+ if (*string_ptr != 0 && strcasecmp (*string_ptr, new_value) != 0)
+ as_warn (_("A different %s was already specified, is now %s"),
+ string_ptr == &mips_arch_string ? "-march" : "-mtune",
+ new_value);
+
+ *string_ptr = new_value;
+}
+
int
md_parse_option (c, arg)
int c;
break;
case OPTION_MIPS1:
- mips_opts.isa = ISA_MIPS1;
+ file_mips_isa = ISA_MIPS1;
break;
case OPTION_MIPS2:
- mips_opts.isa = ISA_MIPS2;
+ file_mips_isa = ISA_MIPS2;
break;
case OPTION_MIPS3:
- mips_opts.isa = ISA_MIPS3;
+ file_mips_isa = ISA_MIPS3;
break;
case OPTION_MIPS4:
- mips_opts.isa = ISA_MIPS4;
+ file_mips_isa = ISA_MIPS4;
break;
case OPTION_MIPS5:
- mips_opts.isa = ISA_MIPS5;
+ file_mips_isa = ISA_MIPS5;
break;
case OPTION_MIPS32:
- mips_opts.isa = ISA_MIPS32;
+ file_mips_isa = ISA_MIPS32;
break;
case OPTION_MIPS64:
- mips_opts.isa = ISA_MIPS64;
+ file_mips_isa = ISA_MIPS64;
break;
case OPTION_MTUNE:
- case OPTION_MARCH:
- case OPTION_MCPU:
- {
- int cpu = CPU_UNKNOWN;
-
- /* Identify the processor type. */
- if (strcasecmp (arg, "default") != 0)
- {
- const struct mips_cpu_info *ci;
-
- ci = mips_cpu_info_from_name (arg);
- if (ci == NULL || ci->is_isa)
- {
- switch (c)
- {
- case OPTION_MTUNE:
- as_fatal (_("invalid architecture -mtune=%s"), arg);
- break;
- case OPTION_MARCH:
- as_fatal (_("invalid architecture -march=%s"), arg);
- break;
- case OPTION_MCPU:
- as_fatal (_("invalid architecture -mcpu=%s"), arg);
- break;
- }
- }
- else
- cpu = ci->cpu;
- }
+ mips_set_option_string (&mips_tune_string, arg);
+ break;
- switch (c)
- {
- case OPTION_MTUNE:
- if (mips_tune != CPU_UNKNOWN && mips_tune != cpu)
- as_warn (_("A different -mtune= was already specified, is now "
- "-mtune=%s"), arg);
- mips_tune = cpu;
- break;
- case OPTION_MARCH:
- if (mips_arch != CPU_UNKNOWN && mips_arch != cpu)
- as_warn (_("A different -march= was already specified, is now "
- "-march=%s"), arg);
- mips_arch = cpu;
- break;
- case OPTION_MCPU:
- if (mips_cpu != CPU_UNKNOWN && mips_cpu != cpu)
- as_warn (_("A different -mcpu= was already specified, is now "
- "-mcpu=%s"), arg);
- mips_cpu = cpu;
- }
- }
+ case OPTION_MARCH:
+ mips_set_option_string (&mips_arch_string, arg);
break;
case OPTION_M4650:
- if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R4650)
- || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R4650))
- as_warn (_("A different -march= or -mtune= was already specified, "
- "is now -m4650"));
- mips_arch = CPU_R4650;
- mips_tune = CPU_R4650;
+ mips_set_option_string (&mips_arch_string, "4650");
+ mips_set_option_string (&mips_tune_string, "4650");
break;
case OPTION_NO_M4650:
break;
case OPTION_M4010:
- if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R4010)
- || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R4010))
- as_warn (_("A different -march= or -mtune= was already specified, "
- "is now -m4010"));
- mips_arch = CPU_R4010;
- mips_tune = CPU_R4010;
+ mips_set_option_string (&mips_arch_string, "4010");
+ mips_set_option_string (&mips_tune_string, "4010");
break;
case OPTION_NO_M4010:
break;
case OPTION_M4100:
- if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_VR4100)
- || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_VR4100))
- as_warn (_("A different -march= or -mtune= was already specified, "
- "is now -m4100"));
- mips_arch = CPU_VR4100;
- mips_tune = CPU_VR4100;
+ mips_set_option_string (&mips_arch_string, "4100");
+ mips_set_option_string (&mips_tune_string, "4100");
break;
case OPTION_NO_M4100:
break;
case OPTION_M3900:
- if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R3900)
- || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R3900))
- as_warn (_("A different -march= or -mtune= was already specified, "
- "is now -m3900"));
- mips_arch = CPU_R3900;
- mips_tune = CPU_R3900;
+ mips_set_option_string (&mips_arch_string, "3900");
+ mips_set_option_string (&mips_tune_string, "3900");
break;
case OPTION_NO_M3900:
as_bad (_("-32 is supported for ELF format only"));
return 0;
}
- mips_opts.abi = O32_ABI;
+ mips_abi = O32_ABI;
break;
case OPTION_N32:
as_bad (_("-n32 is supported for ELF format only"));
return 0;
}
- mips_opts.abi = N32_ABI;
+ mips_abi = N32_ABI;
break;
case OPTION_64:
as_bad (_("-64 is supported for ELF format only"));
return 0;
}
- mips_opts.abi = N64_ABI;
+ mips_abi = N64_ABI;
if (! support_64bit_objects())
as_fatal (_("No compiled in support for 64 bit object file format"));
break;
case OPTION_GP32:
file_mips_gp32 = 1;
- if (mips_opts.abi != O32_ABI)
- mips_opts.abi = NO_ABI;
break;
case OPTION_GP64:
file_mips_gp32 = 0;
- if (mips_opts.abi == O32_ABI)
- mips_opts.abi = NO_ABI;
break;
case OPTION_FP32:
file_mips_fp32 = 1;
- if (mips_opts.abi != O32_ABI)
- mips_opts.abi = NO_ABI;
+ break;
+
+ case OPTION_FP64:
+ file_mips_fp32 = 0;
break;
#ifdef OBJ_ELF
return 0;
}
if (strcmp (arg, "32") == 0)
- mips_opts.abi = O32_ABI;
+ mips_abi = O32_ABI;
else if (strcmp (arg, "o64") == 0)
- mips_opts.abi = O64_ABI;
+ mips_abi = O64_ABI;
else if (strcmp (arg, "n32") == 0)
- mips_opts.abi = N32_ABI;
+ mips_abi = N32_ABI;
else if (strcmp (arg, "64") == 0)
{
- mips_opts.abi = N64_ABI;
+ mips_abi = N64_ABI;
if (! support_64bit_objects())
as_fatal (_("No compiled in support for 64 bit object file "
"format"));
}
else if (strcmp (arg, "eabi") == 0)
- mips_opts.abi = EABI_ABI;
+ mips_abi = EABI_ABI;
else
{
as_fatal (_("invalid abi -mabi=%s"), arg);
mips_7000_hilo_fix = false;
break;
+#ifdef OBJ_ELF
+ case OPTION_MDEBUG:
+ mips_flag_mdebug = true;
+ break;
+
+ case OPTION_NO_MDEBUG:
+ mips_flag_mdebug = false;
+ break;
+#endif /* OBJ_ELF */
+
default:
return 0;
}
return 1;
}
+\f
+/* Set up globals to generate code for the ISA or processor
+ described by INFO. */
static void
-show (stream, string, col_p, first_p)
- FILE *stream;
- char *string;
- int *col_p;
- int *first_p;
+mips_set_architecture (info)
+ const struct mips_cpu_info *info;
{
- if (*first_p)
- {
- fprintf (stream, "%24s", "");
- *col_p = 24;
- }
- else
+ if (info != 0)
{
- fprintf (stream, ", ");
- *col_p += 2;
+ mips_arch_info = info;
+ mips_arch = info->cpu;
+ mips_opts.isa = info->isa;
}
+}
- if (*col_p + strlen (string) > 72)
- {
- fprintf (stream, "\n%24s", "");
- *col_p = 24;
- }
- fprintf (stream, "%s", string);
- *col_p += strlen (string);
+/* Likewise for tuning. */
- *first_p = 0;
+static void
+mips_set_tune (info)
+ const struct mips_cpu_info *info;
+{
+ if (info != 0)
+ {
+ mips_tune_info = info;
+ mips_tune = info->cpu;
+ }
}
+
void
-md_show_usage (stream)
- FILE *stream;
+mips_after_parse_args ()
{
- int column, first;
+ /* GP relative stuff not working for PE */
+ if (strncmp (TARGET_OS, "pe", 2) == 0
+ && g_switch_value != 0)
+ {
+ if (g_switch_seen)
+ as_bad (_("-G not supported in this configuration."));
+ g_switch_value = 0;
+ }
- fprintf (stream, _("\
-MIPS options:\n\
--membedded-pic generate embedded position independent code\n\
--EB generate big endian output\n\
--EL generate little endian output\n\
--g, -g2 do not remove unneeded NOPs or swap branches\n\
--G NUM allow referencing objects up to NUM bytes\n\
- implicitly with the gp register [default 8]\n"));
- fprintf (stream, _("\
--mips1 generate MIPS ISA I instructions\n\
--mips2 generate MIPS ISA II instructions\n\
--mips3 generate MIPS ISA III instructions\n\
--mips4 generate MIPS ISA IV instructions\n\
--mips5 generate MIPS ISA V instructions\n\
--mips32 generate MIPS32 ISA instructions\n\
--mips64 generate MIPS64 ISA instructions\n\
--march=CPU/-mtune=CPU generate code/schedule for CPU, where CPU is one of:\n"));
+ /* The following code determines the architecture and register size.
+ Similar code was added to GCC 3.3 (see override_options() in
+ config/mips/mips.c). The GAS and GCC code should be kept in sync
+ as much as possible. */
- first = 1;
+ if (mips_arch_string != 0)
+ mips_set_architecture (mips_parse_cpu ("-march", mips_arch_string));
- show (stream, "2000", &column, &first);
- show (stream, "3000", &column, &first);
- show (stream, "3900", &column, &first);
- show (stream, "4000", &column, &first);
- show (stream, "4010", &column, &first);
- show (stream, "4100", &column, &first);
- show (stream, "4111", &column, &first);
- show (stream, "4300", &column, &first);
- show (stream, "4400", &column, &first);
- show (stream, "4600", &column, &first);
- show (stream, "4650", &column, &first);
- show (stream, "5000", &column, &first);
- show (stream, "5200", &column, &first);
- show (stream, "5230", &column, &first);
- show (stream, "5231", &column, &first);
- show (stream, "5261", &column, &first);
- show (stream, "5721", &column, &first);
- show (stream, "6000", &column, &first);
- show (stream, "8000", &column, &first);
- show (stream, "10000", &column, &first);
- show (stream, "12000", &column, &first);
- show (stream, "sb1", &column, &first);
- fputc ('\n', stream);
+ if (mips_tune_string != 0)
+ mips_set_tune (mips_parse_cpu ("-mtune", mips_tune_string));
- fprintf (stream, _("\
--mCPU equivalent to -march=CPU -mtune=CPU. Deprecated.\n\
--no-mCPU don't generate code specific to CPU.\n\
- For -mCPU and -no-mCPU, CPU must be one of:\n"));
+ if (file_mips_isa != ISA_UNKNOWN)
+ {
+ /* Handle -mipsN. At this point, file_mips_isa contains the
+ ISA level specified by -mipsN, while mips_opts.isa contains
+ the -march selection (if any). */
+ if (mips_arch_info != 0)
+ {
+ /* -march takes precedence over -mipsN, since it is more descriptive.
+ There's no harm in specifying both as long as the ISA levels
+ are the same. */
+ if (file_mips_isa != mips_opts.isa)
+ as_bad (_("-%s conflicts with the other architecture options, which imply -%s"),
+ mips_cpu_info_from_isa (file_mips_isa)->name,
+ mips_cpu_info_from_isa (mips_opts.isa)->name);
+ }
+ else
+ mips_set_architecture (mips_cpu_info_from_isa (file_mips_isa));
+ }
- first = 1;
+ if (mips_arch_info == 0)
+ mips_set_architecture (mips_parse_cpu ("default CPU",
+ MIPS_CPU_STRING_DEFAULT));
- show (stream, "3900", &column, &first);
- show (stream, "4010", &column, &first);
- show (stream, "4100", &column, &first);
- show (stream, "4650", &column, &first);
- fputc ('\n', stream);
+ if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (mips_opts.isa))
+ as_bad ("-march=%s is not compatible with the selected ABI",
+ mips_arch_info->name);
- fprintf (stream, _("\
--mips16 generate mips16 instructions\n\
--no-mips16 do not generate mips16 instructions\n"));
- fprintf (stream, _("\
--mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
--mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
--O0 remove unneeded NOPs, do not swap branches\n\
--O remove unneeded NOPs and swap branches\n\
--n warn about NOPs generated from macros\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"));
-#ifdef OBJ_ELF
- fprintf (stream, _("\
--KPIC, -call_shared generate SVR4 position independent code\n\
--non_shared do not generate position independent code\n\
--xgot assume a 32 bit GOT\n\
--mabi=ABI create ABI conformant object file for:\n"));
+ /* Optimize for mips_arch, unless -mtune selects a different processor. */
+ if (mips_tune_info == 0)
+ mips_set_tune (mips_arch_info);
- first = 1;
+ if (file_mips_gp32 >= 0)
+ {
+ /* The user specified the size of the integer registers. Make sure
+ it agrees with the ABI and ISA. */
+ if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
+ as_bad (_("-mgp64 used with a 32-bit processor"));
+ else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
+ as_bad (_("-mgp32 used with a 64-bit ABI"));
+ else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
+ as_bad (_("-mgp64 used with a 32-bit ABI"));
+ }
+ else
+ {
+ /* Infer the integer register size from the ABI and processor.
+ Restrict ourselves to 32-bit registers if that's all the
+ processor has, or if the ABI cannot handle 64-bit registers. */
+ file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
+ || !ISA_HAS_64BIT_REGS (mips_opts.isa));
+ }
- show (stream, "32", &column, &first);
- show (stream, "o64", &column, &first);
- show (stream, "n32", &column, &first);
- show (stream, "64", &column, &first);
- show (stream, "eabi", &column, &first);
+ /* ??? GAS treats single-float processors as though they had 64-bit
+ float registers (although it complains when double-precision
+ instructions are used). As things stand, saying they have 32-bit
+ registers would lead to spurious "register must be even" messages.
+ So here we assume float registers are always the same size as
+ integer ones, unless the user says otherwise. */
+ if (file_mips_fp32 < 0)
+ file_mips_fp32 = file_mips_gp32;
- fputc ('\n', stream);
+ /* End of GCC-shared inference code. */
- fprintf (stream, _("\
--32 create o32 ABI object file (default)\n\
--n32 create n32 ABI object file\n\
--64 create 64 ABI object file\n"));
-#endif
+ /* ??? When do we want this flag to be set? Who uses it? */
+ if (file_mips_gp32 == 1
+ && mips_abi == NO_ABI
+ && ISA_HAS_64BIT_REGS (mips_opts.isa))
+ mips_32bitmode = 1;
+
+ if (mips_opts.isa == ISA_MIPS1 && mips_trap)
+ as_bad (_("trap exception not supported at ISA 1"));
+
+ /* If the selected architecture includes support for ASEs, enable
+ generation of code for them. */
+ if (mips_opts.mips16 == -1)
+ mips_opts.mips16 = (CPU_HAS_MIPS16 (mips_arch)) ? 1 : 0;
+ if (mips_opts.ase_mips3d == -1)
+ mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (mips_arch)) ? 1 : 0;
+ if (mips_opts.ase_mdmx == -1)
+ mips_opts.ase_mdmx = (CPU_HAS_MDMX (mips_arch)) ? 1 : 0;
+
+ file_mips_isa = mips_opts.isa;
+ file_ase_mips16 = mips_opts.mips16;
+ file_ase_mips3d = mips_opts.ase_mips3d;
+ file_ase_mdmx = mips_opts.ase_mdmx;
+ mips_opts.gp32 = file_mips_gp32;
+ mips_opts.fp32 = file_mips_fp32;
+
+ if (HAVE_NEWABI)
+ mips_big_got = 1;
+
+ if (mips_flag_mdebug < 0)
+ {
+#ifdef OBJ_MAYBE_ECOFF
+ if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour)
+ mips_flag_mdebug = 1;
+ else
+#endif /* OBJ_MAYBE_ECOFF */
+ mips_flag_mdebug = 0;
+ }
}
\f
void
return 1;
if (mips_pic != EMBEDDED_PIC
&& (S_IS_WEAK (fixP->fx_addsy)
- || S_IS_EXTERN (fixP->fx_addsy))
+ || S_IS_EXTERNAL (fixP->fx_addsy))
&& !S_IS_COMMON (fixP->fx_addsy))
return 1;
if (symbol_used_in_reloc_p (fixP->fx_addsy)
{
if (mips_need_elf_addend_fixup (fixP))
{
+ reloc_howto_type *howto;
valueT symval = S_GET_VALUE (fixP->fx_addsy);
value -= symval;
- if (value != 0 && ! fixP->fx_pcrel)
+
+ howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+ if (value != 0 && howto->partial_inplace && ! fixP->fx_pcrel)
{
/* In this case, the bfd_install_relocation routine will
incorrectly add the symbol value back in. We just want
leave the matching HI16 in-place addends as zero. */
if (fixP->fx_r_type != BFD_RELOC_HI16_S)
{
- reloc_howto_type *howto;
bfd_vma contents, mask, field;
- howto = bfd_reloc_type_lookup (stdoutput,
- fixP->fx_r_type);
-
contents = bfd_get_bits (fixP->fx_frag->fr_literal
+ fixP->fx_where,
fixP->fx_size * 8,
{
mips_opts.nobopt = 1;
}
- else if (strcmp (name, "mdmx") == 0)
- mips_opts.ase_mdmx = 1;
- else if (strcmp (name, "nomdmx") == 0)
- mips_opts.ase_mdmx = 0;
else if (strcmp (name, "mips16") == 0
|| strcmp (name, "MIPS-16") == 0)
mips_opts.mips16 = 1;
mips_opts.ase_mips3d = 1;
else if (strcmp (name, "nomips3d") == 0)
mips_opts.ase_mips3d = 0;
+ else if (strcmp (name, "mdmx") == 0)
+ mips_opts.ase_mdmx = 1;
+ else if (strcmp (name, "nomdmx") == 0)
+ mips_opts.ase_mdmx = 0;
else if (strncmp (name, "mips", 4) == 0)
{
int isa;
case 0:
mips_opts.gp32 = file_mips_gp32;
mips_opts.fp32 = file_mips_fp32;
- mips_opts.abi = file_mips_abi;
break;
case 1:
case 2:
case 4:
case 5:
case 64:
- /* Loosen ABI register width restriction. */
- if (mips_opts.abi == O32_ABI)
- mips_opts.abi = NO_ABI;
mips_opts.gp32 = 0;
mips_opts.fp32 = 0;
break;
expressionS ex_sym;
int reg1;
int icnt = 0;
- char *sym;
+ char *f;
/* If we are not generating SVR4 PIC code, .cpsetup is ignored.
We also need NewABI support. */
else
++input_line_pointer;
SKIP_WHITESPACE ();
- sym = input_line_pointer;
- while (ISALNUM (*input_line_pointer))
- ++input_line_pointer;
- *input_line_pointer = 0;
-
- ex_sym.X_op = O_symbol;
- ex_sym.X_add_symbol = symbol_find_or_make (sym);
- ex_sym.X_op_symbol = NULL;
- ex_sym.X_add_number = 0;
+ expression (&ex_sym);
if (mips_cpreturn_register == -1)
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
"d,v,t", mips_cpreturn_register, mips_gp_register, 0);
+ /* Ensure there's room for the next two instructions, so that `f'
+ doesn't end up with an address in the wrong frag. */
+ frag_grow (8);
+ f = frag_more (0);
macro_build ((char *) NULL, &icnt, &ex_sym, "lui", "t,u", mips_gp_register,
(int) BFD_RELOC_GPREL16);
- fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
- fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_HI16_S);
+ fix_new (frag_now, f - frag_now->fr_literal,
+ 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+ fix_new (frag_now, f - frag_now->fr_literal,
+ 0, NULL, 0, 0, BFD_RELOC_HI16_S);
+
+ f = frag_more (0);
macro_build ((char *) NULL, &icnt, &ex_sym, "addiu", "t,r,j",
mips_gp_register, mips_gp_register, (int) BFD_RELOC_GPREL16);
- fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
- fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_LO16);
+ fix_new (frag_now, f - frag_now->fr_literal,
+ 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+ fix_new (frag_now, f - frag_now->fr_literal,
+ 0, NULL, 0, 0, BFD_RELOC_LO16);
+
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
HAVE_64BIT_ADDRESSES ? "daddu" : "addu", "d,v,t",
mips_gp_register, mips_gp_register, reg1);
}
mips_gp_register = tc_get_register (0);
+ demand_empty_rest_of_line ();
}
/* Handle the .cprestore pseudo-op. This stores $gp into a given
if (*input_line_pointer++ != '$')
{
as_warn (_("expected `$'"));
- reg = 0;
+ reg = ZERO;
}
else if (ISDIGIT (*input_line_pointer))
{
if (reg < 0 || reg >= 32)
{
as_warn (_("Bad register number"));
- reg = 0;
+ reg = ZERO;
}
}
else
{
if (strncmp (input_line_pointer, "ra", 2) == 0)
- reg = RA;
+ {
+ reg = RA;
+ input_line_pointer += 2;
+ }
else if (strncmp (input_line_pointer, "fp", 2) == 0)
- reg = FP;
+ {
+ reg = FP;
+ input_line_pointer += 2;
+ }
else if (strncmp (input_line_pointer, "sp", 2) == 0)
- reg = SP;
+ {
+ reg = SP;
+ input_line_pointer += 2;
+ }
else if (strncmp (input_line_pointer, "gp", 2) == 0)
- reg = GP;
+ {
+ reg = GP;
+ input_line_pointer += 2;
+ }
else if (strncmp (input_line_pointer, "at", 2) == 0)
- reg = AT;
+ {
+ reg = AT;
+ input_line_pointer += 2;
+ }
+ else if (strncmp (input_line_pointer, "kt0", 3) == 0)
+ {
+ reg = KT0;
+ input_line_pointer += 3;
+ }
+ else if (strncmp (input_line_pointer, "kt1", 3) == 0)
+ {
+ reg = KT1;
+ input_line_pointer += 3;
+ }
+ else if (strncmp (input_line_pointer, "zero", 4) == 0)
+ {
+ reg = ZERO;
+ input_line_pointer += 4;
+ }
else
{
as_warn (_("Unrecognized register name"));
- reg = 0;
+ reg = ZERO;
+ while (ISALNUM(*input_line_pointer))
+ input_line_pointer++;
}
- input_line_pointer += 2;
}
if (frame)
{
/* A global or weak symbol is treated as external. */
&& (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| (! S_IS_WEAK (sym)
- && (! S_IS_EXTERN (sym) || mips_pic == EMBEDDED_PIC)))
+ && (! S_IS_EXTERNAL (sym)
+ || mips_pic == EMBEDDED_PIC)))
#endif
);
}
/* Prevent all adjustments to global symbols. */
if (OUTPUT_FLAVOR == bfd_target_elf_flavour
&& mips_pic != EMBEDDED_PIC
- && (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+ && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
return 0;
#endif
if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
stop md_apply_fix3 from subtracting twice in the first place since
the fake addend is required for variant frags above. */
if (fixp->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour
- && code == BFD_RELOC_GPREL16
+ && (code == BFD_RELOC_GPREL16 || code == BFD_RELOC_MIPS16_GPREL)
&& reloc->addend != 0
&& mips_need_elf_addend_fixup (fixp))
reloc->addend += S_GET_VALUE (fixp->fx_addsy);
mips_elf_final_processing ()
{
/* Write out the register information. */
- if (file_mips_abi != N64_ABI)
+ if (mips_abi != N64_ABI)
{
Elf32_RegInfo s;
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
/* Set MIPS ELF flags for ASEs. */
+ if (file_ase_mips16)
+ elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
#if 0 /* XXX FIXME */
if (file_ase_mips3d)
elf_elfheader (stdoutput)->e_flags |= ???;
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
/* Set the MIPS ELF ABI flags. */
- if (file_mips_abi == NO_ABI)
- ;
- else if (file_mips_abi == O32_ABI)
+ if (mips_abi == O32_ABI && USE_E_MIPS_ABI_O32)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
- else if (file_mips_abi == O64_ABI)
+ else if (mips_abi == O64_ABI)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
- else if (file_mips_abi == EABI_ABI)
+ else if (mips_abi == EABI_ABI)
{
- if (mips_eabi64)
+ if (!file_mips_gp32)
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
else
elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
}
- else if (file_mips_abi == N32_ABI)
+ else if (mips_abi == N32_ABI)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
/* Nothing to do for N64_ABI. */
}
/* The .file directive; just like the usual .file directive, but there
- is an initial number which is the ECOFF file index. */
+ is an initial number which is the ECOFF file index. In the non-ECOFF
+ case .file implies DWARF-2. */
static void
-s_file (x)
+s_mips_file (x)
int x ATTRIBUTE_UNUSED;
{
- get_number ();
- s_app_file (0);
+ static int first_file_directive = 0;
+
+ if (ECOFF_DEBUGGING)
+ {
+ get_number ();
+ s_app_file (0);
+ }
+ else
+ {
+ char *filename;
+
+ filename = dwarf2_directive_file (0);
+
+ /* Versions of GCC up to 3.1 start files with a ".file"
+ directive even for stabs output. Make sure that this
+ ".file" is handled. Note that you need a version of GCC
+ after 3.1 in order to support DWARF-2 on MIPS. */
+ if (filename != NULL && ! first_file_directive)
+ {
+ (void) new_logical_line (filename, -1);
+ s_app_file_string (filename);
+ }
+ first_file_directive = 1;
+ }
+}
+
+/* The .loc directive, implying DWARF-2. */
+
+static void
+s_mips_loc (x)
+ int x ATTRIBUTE_UNUSED;
+{
+ if (!ECOFF_DEBUGGING)
+ dwarf2_directive_loc (0);
}
/* The .end directive. */
assert (S_GET_NAME (p));
if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->isym)))
as_warn (_(".end symbol does not match .ent symbol."));
+
+ if (debug_type == DEBUG_STABS)
+ stabs_generate_asm_endfunc (S_GET_NAME (p),
+ S_GET_NAME (p));
}
else
as_warn (_(".end directive missing or unknown symbol"));
-#ifdef MIPS_STABS_ELF
- {
- segT saved_seg = now_seg;
- subsegT saved_subseg = now_subseg;
- valueT dot;
- expressionS exp;
- char *fragp;
+#ifdef OBJ_ELF
+ /* Generate a .pdr section. */
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+ {
+ segT saved_seg = now_seg;
+ subsegT saved_subseg = now_subseg;
+ valueT dot;
+ expressionS exp;
+ char *fragp;
- dot = frag_now_fix ();
+ dot = frag_now_fix ();
#ifdef md_flush_pending_output
- md_flush_pending_output ();
+ md_flush_pending_output ();
#endif
- assert (pdr_seg);
- subseg_set (pdr_seg, 0);
+ assert (pdr_seg);
+ subseg_set (pdr_seg, 0);
- /* Write the symbol. */
- exp.X_op = O_symbol;
- exp.X_add_symbol = p;
- exp.X_add_number = 0;
- emit_expr (&exp, 4);
+ /* Write the symbol. */
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = p;
+ exp.X_add_number = 0;
+ emit_expr (&exp, 4);
- fragp = frag_more (7 * 4);
+ fragp = frag_more (7 * 4);
- md_number_to_chars (fragp, (valueT) cur_proc_ptr->reg_mask, 4);
- md_number_to_chars (fragp + 4, (valueT) cur_proc_ptr->reg_offset, 4);
- md_number_to_chars (fragp + 8, (valueT) cur_proc_ptr->fpreg_mask, 4);
- md_number_to_chars (fragp + 12, (valueT) cur_proc_ptr->fpreg_offset, 4);
- md_number_to_chars (fragp + 16, (valueT) cur_proc_ptr->frame_offset, 4);
- md_number_to_chars (fragp + 20, (valueT) cur_proc_ptr->frame_reg, 4);
- md_number_to_chars (fragp + 24, (valueT) cur_proc_ptr->pc_reg, 4);
+ md_number_to_chars (fragp, (valueT) cur_proc_ptr->reg_mask, 4);
+ md_number_to_chars (fragp + 4, (valueT) cur_proc_ptr->reg_offset, 4);
+ md_number_to_chars (fragp + 8, (valueT) cur_proc_ptr->fpreg_mask, 4);
+ md_number_to_chars (fragp + 12, (valueT) cur_proc_ptr->fpreg_offset, 4);
+ md_number_to_chars (fragp + 16, (valueT) cur_proc_ptr->frame_offset, 4);
+ md_number_to_chars (fragp + 20, (valueT) cur_proc_ptr->frame_reg, 4);
+ md_number_to_chars (fragp + 24, (valueT) cur_proc_ptr->pc_reg, 4);
- subseg_set (saved_seg, saved_subseg);
- }
-#endif /* MIPS_STABS_ELF */
+ subseg_set (saved_seg, saved_subseg);
+ }
+#endif /* OBJ_ELF */
cur_proc_ptr = NULL;
}
symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
++numprocs;
+
+ if (debug_type == DEBUG_STABS)
+ stabs_generate_asm_func (S_GET_NAME (symbolP),
+ S_GET_NAME (symbolP));
}
demand_empty_rest_of_line ();
s_mips_frame (ignore)
int ignore ATTRIBUTE_UNUSED;
{
-#ifdef MIPS_STABS_ELF
+#ifdef OBJ_ELF
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+ {
+ long val;
+
+ if (cur_proc_ptr == (procS *) NULL)
+ {
+ as_warn (_(".frame outside of .ent"));
+ demand_empty_rest_of_line ();
+ return;
+ }
- long val;
+ cur_proc_ptr->frame_reg = tc_get_register (1);
- if (cur_proc_ptr == (procS *) NULL)
- {
- as_warn (_(".frame outside of .ent"));
- demand_empty_rest_of_line ();
- return;
- }
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer++ != ','
+ || get_absolute_expression_and_terminator (&val) != ',')
+ {
+ as_warn (_("Bad .frame directive"));
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+ return;
+ }
- cur_proc_ptr->frame_reg = tc_get_register (1);
+ cur_proc_ptr->frame_offset = val;
+ cur_proc_ptr->pc_reg = tc_get_register (0);
- SKIP_WHITESPACE ();
- if (*input_line_pointer++ != ','
- || get_absolute_expression_and_terminator (&val) != ',')
- {
- as_warn (_("Bad .frame directive"));
- --input_line_pointer;
demand_empty_rest_of_line ();
- return;
}
-
- cur_proc_ptr->frame_offset = val;
- cur_proc_ptr->pc_reg = tc_get_register (0);
-
- demand_empty_rest_of_line ();
-#else
- s_ignore (ignore);
-#endif /* MIPS_STABS_ELF */
+ else
+#endif /* OBJ_ELF */
+ s_ignore (ignore);
}
/* The .fmask and .mask directives. If the mdebug section is present
s_mips_mask (reg_type)
char reg_type;
{
-#ifdef MIPS_STABS_ELF
- long mask, off;
-
- if (cur_proc_ptr == (procS *) NULL)
+#ifdef OBJ_ELF
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
{
- as_warn (_(".mask/.fmask outside of .ent"));
- demand_empty_rest_of_line ();
- return;
- }
+ long mask, off;
- if (get_absolute_expression_and_terminator (&mask) != ',')
- {
- as_warn (_("Bad .mask/.fmask directive"));
- --input_line_pointer;
- demand_empty_rest_of_line ();
- return;
- }
+ if (cur_proc_ptr == (procS *) NULL)
+ {
+ as_warn (_(".mask/.fmask outside of .ent"));
+ demand_empty_rest_of_line ();
+ return;
+ }
- off = get_absolute_expression ();
+ if (get_absolute_expression_and_terminator (&mask) != ',')
+ {
+ as_warn (_("Bad .mask/.fmask directive"));
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+ return;
+ }
- if (reg_type == 'F')
- {
- cur_proc_ptr->fpreg_mask = mask;
- cur_proc_ptr->fpreg_offset = off;
+ off = get_absolute_expression ();
+
+ if (reg_type == 'F')
+ {
+ cur_proc_ptr->fpreg_mask = mask;
+ cur_proc_ptr->fpreg_offset = off;
+ }
+ else
+ {
+ cur_proc_ptr->reg_mask = mask;
+ cur_proc_ptr->reg_offset = off;
+ }
+
+ demand_empty_rest_of_line ();
}
else
- {
- cur_proc_ptr->reg_mask = mask;
- cur_proc_ptr->reg_offset = off;
- }
-
- demand_empty_rest_of_line ();
-#else
- s_ignore (reg_type);
-#endif /* MIPS_STABS_ELF */
+#endif /* OBJ_ELF */
+ s_ignore (reg_type);
}
/* The .loc directive. */
}
#endif
-/* CPU name/ISA/number mapping table.
-
- Entries are grouped by type. The first matching CPU or ISA entry
- gets chosen by CPU or ISA, so it should be the 'canonical' name
- for that type. Entries after that within the type are sorted
- alphabetically.
+/* A table describing all the processors gas knows about. Names are
+ matched in the order listed.
- Case is ignored in comparison, so put the canonical entry in the
- appropriate case but everything else in lower case to ease eye pain. */
+ To ease comparison, please keep this table in the same order as
+ gcc's mips_cpu_info_table[]. */
static const struct mips_cpu_info mips_cpu_info_table[] =
{
- /* MIPS1 ISA */
- { "MIPS1", 1, ISA_MIPS1, CPU_R3000, },
- { "mips", 1, ISA_MIPS1, CPU_R3000, },
+ /* Entries for generic ISAs */
+ { "mips1", 1, ISA_MIPS1, CPU_R3000 },
+ { "mips2", 1, ISA_MIPS2, CPU_R6000 },
+ { "mips3", 1, ISA_MIPS3, CPU_R4000 },
+ { "mips4", 1, ISA_MIPS4, CPU_R8000 },
+ { "mips5", 1, ISA_MIPS5, CPU_MIPS5 },
+ { "mips32", 1, ISA_MIPS32, CPU_MIPS32 },
+ { "mips64", 1, ISA_MIPS64, CPU_MIPS64 },
+
+ /* MIPS I */
+ { "r3000", 0, ISA_MIPS1, CPU_R3000 },
+ { "r2000", 0, ISA_MIPS1, CPU_R3000 },
+ { "r3900", 0, ISA_MIPS1, CPU_R3900 },
+
+ /* MIPS II */
+ { "r6000", 0, ISA_MIPS2, CPU_R6000 },
+
+ /* MIPS III */
+ { "r4000", 0, ISA_MIPS3, CPU_R4000 },
+ { "r4010", 0, ISA_MIPS2, CPU_R4010 },
+ { "vr4100", 0, ISA_MIPS3, CPU_VR4100 },
+ { "vr4111", 0, ISA_MIPS3, CPU_R4111 },
+ { "vr4300", 0, ISA_MIPS3, CPU_R4300 },
+ { "r4400", 0, ISA_MIPS3, CPU_R4400 },
+ { "r4600", 0, ISA_MIPS3, CPU_R4600 },
+ { "orion", 0, ISA_MIPS3, CPU_R4600 },
+ { "r4650", 0, ISA_MIPS3, CPU_R4650 },
+
+ /* MIPS IV */
+ { "r8000", 0, ISA_MIPS4, CPU_R8000 },
+ { "r10000", 0, ISA_MIPS4, CPU_R10000 },
+ { "r12000", 0, ISA_MIPS4, CPU_R12000 },
+ { "vr5000", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5200", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5230", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5231", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5261", 0, ISA_MIPS4, CPU_R5000 },
+ { "rm5721", 0, ISA_MIPS4, CPU_R5000 },
+ { "r7000", 0, ISA_MIPS4, CPU_R5000 },
+
+ /* MIPS 32 */
+ { "4kc", 0, ISA_MIPS32, CPU_MIPS32, },
+ { "4km", 0, ISA_MIPS32, CPU_MIPS32 },
+ { "4kp", 0, ISA_MIPS32, CPU_MIPS32 },
- /* MIPS2 ISA */
- { "MIPS2", 1, ISA_MIPS2, CPU_R6000, },
+ /* MIPS 64 */
+ { "5kc", 0, ISA_MIPS64, CPU_MIPS64 },
+ { "20kc", 0, ISA_MIPS64, CPU_MIPS64 },
- /* MIPS3 ISA */
- { "MIPS3", 1, ISA_MIPS3, CPU_R4000, },
+ /* Broadcom SB-1 CPU core */
+ { "sb1", 0, ISA_MIPS64, CPU_SB1 },
- /* MIPS4 ISA */
- { "MIPS4", 1, ISA_MIPS4, CPU_R8000, },
+ /* End marker */
+ { NULL, 0, 0, 0 }
+};
- /* MIPS5 ISA */
- { "MIPS5", 1, ISA_MIPS5, CPU_MIPS5, },
- { "Generic-MIPS5", 0, ISA_MIPS5, CPU_MIPS5, },
- /* MIPS32 ISA */
- { "MIPS32", 1, ISA_MIPS32, CPU_MIPS32, },
- { "mipsisa32", 0, ISA_MIPS32, CPU_MIPS32, },
- { "Generic-MIPS32", 0, ISA_MIPS32, CPU_MIPS32, },
- { "4kc", 0, ISA_MIPS32, CPU_MIPS32, },
- { "4km", 0, ISA_MIPS32, CPU_MIPS32, },
- { "4kp", 0, ISA_MIPS32, CPU_MIPS32, },
-
- /* For historical reasons. */
- { "MIPS64", 1, ISA_MIPS3, CPU_R4000, },
-
- /* MIPS64 ISA */
- { "mipsisa64", 1, ISA_MIPS64, CPU_MIPS64, },
- { "Generic-MIPS64", 0, ISA_MIPS64, CPU_MIPS64, },
- { "5kc", 0, ISA_MIPS64, CPU_MIPS64, },
- { "20kc", 0, ISA_MIPS64, CPU_MIPS64, },
-
- /* R2000 CPU */
- { "R2000", 0, ISA_MIPS1, CPU_R2000, },
- { "2000", 0, ISA_MIPS1, CPU_R2000, },
- { "2k", 0, ISA_MIPS1, CPU_R2000, },
- { "r2k", 0, ISA_MIPS1, CPU_R2000, },
-
- /* R3000 CPU */
- { "R3000", 0, ISA_MIPS1, CPU_R3000, },
- { "3000", 0, ISA_MIPS1, CPU_R3000, },
- { "3k", 0, ISA_MIPS1, CPU_R3000, },
- { "r3k", 0, ISA_MIPS1, CPU_R3000, },
-
- /* TX3900 CPU */
- { "R3900", 0, ISA_MIPS1, CPU_R3900, },
- { "3900", 0, ISA_MIPS1, CPU_R3900, },
- { "mipstx39", 0, ISA_MIPS1, CPU_R3900, },
-
- /* R4000 CPU */
- { "R4000", 0, ISA_MIPS3, CPU_R4000, },
- { "4000", 0, ISA_MIPS3, CPU_R4000, },
- { "4k", 0, ISA_MIPS3, CPU_R4000, }, /* beware */
- { "r4k", 0, ISA_MIPS3, CPU_R4000, },
-
- /* R4010 CPU */
- { "R4010", 0, ISA_MIPS2, CPU_R4010, },
- { "4010", 0, ISA_MIPS2, CPU_R4010, },
-
- /* R4400 CPU */
- { "R4400", 0, ISA_MIPS3, CPU_R4400, },
- { "4400", 0, ISA_MIPS3, CPU_R4400, },
-
- /* R4600 CPU */
- { "R4600", 0, ISA_MIPS3, CPU_R4600, },
- { "4600", 0, ISA_MIPS3, CPU_R4600, },
- { "mips64orion", 0, ISA_MIPS3, CPU_R4600, },
- { "orion", 0, ISA_MIPS3, CPU_R4600, },
-
- /* R4650 CPU */
- { "R4650", 0, ISA_MIPS3, CPU_R4650, },
- { "4650", 0, ISA_MIPS3, CPU_R4650, },
-
- /* R6000 CPU */
- { "R6000", 0, ISA_MIPS2, CPU_R6000, },
- { "6000", 0, ISA_MIPS2, CPU_R6000, },
- { "6k", 0, ISA_MIPS2, CPU_R6000, },
- { "r6k", 0, ISA_MIPS2, CPU_R6000, },
-
- /* R8000 CPU */
- { "R8000", 0, ISA_MIPS4, CPU_R8000, },
- { "8000", 0, ISA_MIPS4, CPU_R8000, },
- { "8k", 0, ISA_MIPS4, CPU_R8000, },
- { "r8k", 0, ISA_MIPS4, CPU_R8000, },
-
- /* R10000 CPU */
- { "R10000", 0, ISA_MIPS4, CPU_R10000, },
- { "10000", 0, ISA_MIPS4, CPU_R10000, },
- { "10k", 0, ISA_MIPS4, CPU_R10000, },
- { "r10k", 0, ISA_MIPS4, CPU_R10000, },
-
- /* R12000 CPU */
- { "R12000", 0, ISA_MIPS4, CPU_R12000, },
- { "12000", 0, ISA_MIPS4, CPU_R12000, },
- { "12k", 0, ISA_MIPS4, CPU_R12000, },
- { "r12k", 0, ISA_MIPS4, CPU_R12000, },
-
- /* VR4100 CPU */
- { "VR4100", 0, ISA_MIPS3, CPU_VR4100, },
- { "4100", 0, ISA_MIPS3, CPU_VR4100, },
- { "mips64vr4100", 0, ISA_MIPS3, CPU_VR4100, },
- { "r4100", 0, ISA_MIPS3, CPU_VR4100, },
-
- /* VR4111 CPU */
- { "VR4111", 0, ISA_MIPS3, CPU_R4111, },
- { "4111", 0, ISA_MIPS3, CPU_R4111, },
- { "mips64vr4111", 0, ISA_MIPS3, CPU_R4111, },
- { "r4111", 0, ISA_MIPS3, CPU_R4111, },
-
- /* VR4300 CPU */
- { "VR4300", 0, ISA_MIPS3, CPU_R4300, },
- { "4300", 0, ISA_MIPS3, CPU_R4300, },
- { "mips64vr4300", 0, ISA_MIPS3, CPU_R4300, },
- { "r4300", 0, ISA_MIPS3, CPU_R4300, },
-
- /* VR5000 CPU */
- { "VR5000", 0, ISA_MIPS4, CPU_R5000, },
- { "5000", 0, ISA_MIPS4, CPU_R5000, },
- { "5k", 0, ISA_MIPS4, CPU_R5000, },
- { "mips64vr5000", 0, ISA_MIPS4, CPU_R5000, },
- { "r5000", 0, ISA_MIPS4, CPU_R5000, },
- { "r5200", 0, ISA_MIPS4, CPU_R5000, },
- { "rm5200", 0, ISA_MIPS4, CPU_R5000, },
- { "r5230", 0, ISA_MIPS4, CPU_R5000, },
- { "rm5230", 0, ISA_MIPS4, CPU_R5000, },
- { "r5231", 0, ISA_MIPS4, CPU_R5000, },
- { "rm5231", 0, ISA_MIPS4, CPU_R5000, },
- { "r5261", 0, ISA_MIPS4, CPU_R5000, },
- { "rm5261", 0, ISA_MIPS4, CPU_R5000, },
- { "r5721", 0, ISA_MIPS4, CPU_R5000, },
- { "rm5721", 0, ISA_MIPS4, CPU_R5000, },
- { "r5k", 0, ISA_MIPS4, CPU_R5000, },
- { "r7000", 0, ISA_MIPS4, CPU_R5000, },
-
- /* Broadcom SB-1 CPU */
- { "SB-1", 0, ISA_MIPS64, CPU_SB1, },
- { "sb-1250", 0, ISA_MIPS64, CPU_SB1, },
- { "sb1", 0, ISA_MIPS64, CPU_SB1, },
- { "sb1250", 0, ISA_MIPS64, CPU_SB1, },
-
- /* End marker. */
- { NULL, 0, 0, 0, },
-};
+/* Return true if GIVEN is the same as CANONICAL, or if it is CANONICAL
+ with a final "000" replaced by "k". Ignore case.
+
+ Note: this function is shared between GCC and GAS. */
+
+static boolean
+mips_strict_matching_cpu_name_p (canonical, given)
+ const char *canonical, *given;
+{
+ while (*given != 0 && TOLOWER (*given) == TOLOWER (*canonical))
+ given++, canonical++;
+
+ return ((*given == 0 && *canonical == 0)
+ || (strcmp (canonical, "000") == 0 && strcasecmp (given, "k") == 0));
+}
+
+
+/* Return true if GIVEN matches CANONICAL, where GIVEN is a user-supplied
+ CPU name. We've traditionally allowed a lot of variation here.
+
+ Note: this function is shared between GCC and GAS. */
+
+static boolean
+mips_matching_cpu_name_p (canonical, given)
+ const char *canonical, *given;
+{
+ /* First see if the name matches exactly, or with a final "000"
+ turned into "k". */
+ if (mips_strict_matching_cpu_name_p (canonical, given))
+ return true;
+
+ /* If not, try comparing based on numerical designation alone.
+ See if GIVEN is an unadorned number, or 'r' followed by a number. */
+ if (TOLOWER (*given) == 'r')
+ given++;
+ if (!ISDIGIT (*given))
+ return false;
+
+ /* Skip over some well-known prefixes in the canonical name,
+ hoping to find a number there too. */
+ if (TOLOWER (canonical[0]) == 'v' && TOLOWER (canonical[1]) == 'r')
+ canonical += 2;
+ else if (TOLOWER (canonical[0]) == 'r' && TOLOWER (canonical[1]) == 'm')
+ canonical += 2;
+ else if (TOLOWER (canonical[0]) == 'r')
+ canonical += 1;
+
+ return mips_strict_matching_cpu_name_p (canonical, given);
+}
+
+
+/* Parse an option that takes the name of a processor as its argument.
+ OPTION is the name of the option and CPU_STRING is the argument.
+ Return the corresponding processor enumeration if the CPU_STRING is
+ recognized, otherwise report an error and return null.
+
+ A similar function exists in GCC. */
static const struct mips_cpu_info *
-mips_cpu_info_from_name (name)
- const char *name;
+mips_parse_cpu (option, cpu_string)
+ const char *option, *cpu_string;
{
- int i;
+ const struct mips_cpu_info *p;
- for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
- if (strcasecmp (name, mips_cpu_info_table[i].name) == 0)
- return (&mips_cpu_info_table[i]);
+ /* 'from-abi' selects the most compatible architecture for the given
+ ABI: MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs. For the
+ EABIs, we have to decide whether we're using the 32-bit or 64-bit
+ version. Look first at the -mgp options, if given, otherwise base
+ the choice on MIPS_DEFAULT_64BIT.
- return NULL;
+ Treat NO_ABI like the EABIs. One reason to do this is that the
+ plain 'mips' and 'mips64' configs have 'from-abi' as their default
+ architecture. This code picks MIPS I for 'mips' and MIPS III for
+ 'mips64', just as we did in the days before 'from-abi'. */
+ if (strcasecmp (cpu_string, "from-abi") == 0)
+ {
+ if (ABI_NEEDS_32BIT_REGS (mips_abi))
+ return mips_cpu_info_from_isa (ISA_MIPS1);
+
+ if (ABI_NEEDS_64BIT_REGS (mips_abi))
+ return mips_cpu_info_from_isa (ISA_MIPS3);
+
+ if (file_mips_gp32 >= 0)
+ return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
+
+ return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
+ ? ISA_MIPS3
+ : ISA_MIPS1);
+ }
+
+ /* 'default' has traditionally been a no-op. Probably not very useful. */
+ if (strcasecmp (cpu_string, "default") == 0)
+ return 0;
+
+ for (p = mips_cpu_info_table; p->name != 0; p++)
+ if (mips_matching_cpu_name_p (p->name, cpu_string))
+ return p;
+
+ as_bad ("Bad value (%s) for %s", cpu_string, option);
+ return 0;
}
+/* Return the canonical processor information for ISA (a member of the
+ ISA_MIPS* enumeration). */
+
static const struct mips_cpu_info *
mips_cpu_info_from_isa (isa)
int isa;
for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
if (mips_cpu_info_table[i].is_isa
- && isa == mips_cpu_info_table[i].isa)
+ && isa == mips_cpu_info_table[i].isa)
return (&mips_cpu_info_table[i]);
return NULL;
}
+\f
+static void
+show (stream, string, col_p, first_p)
+ FILE *stream;
+ const char *string;
+ int *col_p;
+ int *first_p;
+{
+ if (*first_p)
+ {
+ fprintf (stream, "%24s", "");
+ *col_p = 24;
+ }
+ else
+ {
+ fprintf (stream, ", ");
+ *col_p += 2;
+ }
-static const struct mips_cpu_info *
-mips_cpu_info_from_cpu (cpu)
- int cpu;
+ if (*col_p + strlen (string) > 72)
+ {
+ fprintf (stream, "\n%24s", "");
+ *col_p = 24;
+ }
+
+ fprintf (stream, "%s", string);
+ *col_p += strlen (string);
+
+ *first_p = 0;
+}
+
+void
+md_show_usage (stream)
+ FILE *stream;
{
- int i;
+ int column, first;
+ size_t i;
+
+ fprintf (stream, _("\
+MIPS options:\n\
+-membedded-pic generate embedded position independent code\n\
+-EB generate big endian output\n\
+-EL generate little endian output\n\
+-g, -g2 do not remove unneeded NOPs or swap branches\n\
+-G NUM allow referencing objects up to NUM bytes\n\
+ implicitly with the gp register [default 8]\n"));
+ fprintf (stream, _("\
+-mips1 generate MIPS ISA I instructions\n\
+-mips2 generate MIPS ISA II instructions\n\
+-mips3 generate MIPS ISA III instructions\n\
+-mips4 generate MIPS ISA IV instructions\n\
+-mips5 generate MIPS ISA V instructions\n\
+-mips32 generate MIPS32 ISA instructions\n\
+-mips64 generate MIPS64 ISA instructions\n\
+-march=CPU/-mtune=CPU generate code/schedule for CPU, where CPU is one of:\n"));
+
+ first = 1;
for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
- if (!mips_cpu_info_table[i].is_isa
- && cpu == mips_cpu_info_table[i].cpu)
- return (&mips_cpu_info_table[i]);
+ show (stream, mips_cpu_info_table[i].name, &column, &first);
+ show (stream, "from-abi", &column, &first);
+ fputc ('\n', stream);
- return NULL;
+ fprintf (stream, _("\
+-mCPU equivalent to -march=CPU -mtune=CPU. Deprecated.\n\
+-no-mCPU don't generate code specific to CPU.\n\
+ For -mCPU and -no-mCPU, CPU must be one of:\n"));
+
+ first = 1;
+
+ show (stream, "3900", &column, &first);
+ show (stream, "4010", &column, &first);
+ show (stream, "4100", &column, &first);
+ show (stream, "4650", &column, &first);
+ fputc ('\n', stream);
+
+ fprintf (stream, _("\
+-mips16 generate mips16 instructions\n\
+-no-mips16 do not generate mips16 instructions\n"));
+ fprintf (stream, _("\
+-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
+-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
+-O0 remove unneeded NOPs, do not swap branches\n\
+-O remove unneeded NOPs and swap branches\n\
+-n warn about NOPs generated from macros\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"));
+#ifdef OBJ_ELF
+ fprintf (stream, _("\
+-KPIC, -call_shared generate SVR4 position independent code\n\
+-non_shared do not generate position independent code\n\
+-xgot assume a 32 bit GOT\n\
+-mabi=ABI create ABI conformant object file for:\n"));
+
+ first = 1;
+
+ show (stream, "32", &column, &first);
+ show (stream, "o64", &column, &first);
+ show (stream, "n32", &column, &first);
+ show (stream, "64", &column, &first);
+ show (stream, "eabi", &column, &first);
+
+ fputc ('\n', stream);
+
+ fprintf (stream, _("\
+-32 create o32 ABI object file (default)\n\
+-n32 create n32 ABI object file\n\
+-64 create 64 ABI object file\n"));
+#endif
}