Nuts. Checked in wrong version of previous patch. Fixed.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 797b365330034d4f5d9ffc39b0dc4ab1a29bbab6..906641dfe58d3e03aaf4ee15cd733bff3cacfc55 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   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
@@ -54,7 +55,6 @@ static int mips_output_flavor () { return OUTPUT_FLAVOR; }
 #undef S_GET_SIZE
 #undef S_SET_ALIGN
 #undef S_SET_SIZE
-#undef TARGET_SYMBOL_FIELDS
 #undef obj_frob_file
 #undef obj_frob_file_after_relocs
 #undef obj_frob_symbol
@@ -110,6 +110,7 @@ extern int target_big_endian;
 static int mips_64;
 
 /* The default target format to use.  */
+
 const char *
 mips_target_format ()
 {
@@ -119,10 +120,19 @@ mips_target_format ()
       return target_big_endian ? "a.out-mips-big" : "a.out-mips-little";
     case bfd_target_ecoff_flavour:
       return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
+    case bfd_target_coff_flavour:
+      return "pe-mips";
     case bfd_target_elf_flavour:
+#ifdef TE_TMIPS
+      /* This is traditional mips */
+      return (target_big_endian
+             ? (mips_64 ? "elf64-tradbigmips" : "elf32-tradbigmips")
+             : (mips_64 ? "elf64-tradlittlemips" : "elf32-tradlittlemips"));
+#else
       return (target_big_endian
              ? (mips_64 ? "elf64-bigmips" : "elf32-bigmips")
              : (mips_64 ? "elf64-littlemips" : "elf32-littlemips"));
+#endif
     default:
       abort ();
       return NULL;
@@ -134,17 +144,15 @@ mips_target_format ()
                            ? ".data" \
                            : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
                            ? ".rdata" \
+                           : OUTPUT_FLAVOR == bfd_target_coff_flavour \
+                           ? ".rdata" \
                            : OUTPUT_FLAVOR == bfd_target_elf_flavour \
                            ? ".rodata" \
                            : (abort (), ""))
 
 /* 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
-   reliable.
-
-   FIXME: The CPU specific variables (mips_4010, et. al.) should
-   probably be in here as well, and there should probably be some way
-   to set them.  */
+   reliable.  */
 
 struct mips_set_options
 {
@@ -181,10 +189,13 @@ struct mips_set_options
 };
 
 /* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa and mips16 fields to -1 to indicate that
-   they have not been initialized.  */
+   that we must set the isa field to ISA_UNKNOWN and the mips16 field to
+   -1 to indicate that they have not been initialized.  */
 
-static struct mips_set_options mips_opts = { -1, -1 };
+static struct mips_set_options mips_opts =
+{
+  ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0
+};
 
 /* These variables are filled in with the masks of registers used.
    The object format code reads them and puts them in the appropriate
@@ -193,109 +204,99 @@ unsigned long mips_gprmask;
 unsigned long mips_cprmask[4];
 
 /* MIPS ISA we are using for this output file.  */
-static int file_mips_isa;
-
-/* The CPU type as a number: 2000, 3000, 4000, 4400, etc.  */
-static int mips_cpu = -1;
-
-/* The argument of the -mabi= flag. */
-static char* mips_abi_string = 0;
-
-/* Wether we should mark the file EABI64 or EABI32. */
-static int mips_eabi64 = 0;
-
-/* Whether the 4650 instructions (mad/madu) are permitted.  */
-static int mips_4650 = -1;
-
-/* Whether the 4010 instructions are permitted.  */
-static int mips_4010 = -1;
-
-/* Whether the 4100 MADD16 and DMADD16 are permitted. */
-static int mips_4100 = -1;
-
-/* start-sanitize-vr4xxx */
-/* Whether NEC 4121 instructions are permitted. */
-static int mips_4121 = -1;
+static int file_mips_isa = ISA_UNKNOWN;
 
-/* end-sanitize-vr4xxx */
-/* start-sanitize-vr4320 */
-/* Whether NEC vr4320 instructions are permitted. */
-static int mips_4320 = -1;
+/* The argument of the -mcpu= flag.  Historical for code generation.  */
+static int mips_cpu = CPU_UNKNOWN;
 
-/* end-sanitize-vr4320 */
-/* start-sanitize-cygnus */
-/* Whether NEC vr5400 instructions are permitted. */
-static int mips_5400 = -1;
+/* The argument of the -march= flag.  The architecture we are assembling.  */
+static int mips_arch = CPU_UNKNOWN;
 
-/* end-sanitize-cygnus */
-/* start-sanitize-r5900 */
-/* Whether Toshiba r5900 instructions are permitted. */
-static int mips_5900 = -1;
+/* The argument of the -mtune= flag.  The architecture for which we
+   are optimizing.  */
+static int mips_tune = CPU_UNKNOWN;
 
-/* end-sanitize-r5900 */
-/* Whether Toshiba r3900 instructions are permitted. */
-static int mips_3900 = -1;
+/* The argument of the -mabi= flag.  */
+static char * mips_abi_string = NULL;
 
-/* start-sanitize-tx49 */
-/* Whether Toshiba r4900 instructions are permitted. */
-static int mips_4900 = -1;
-
-/* end-sanitize-tx49 */
-/* start-sanitize-tx19 */
-/* The tx19 (r1900) is a mips16 decoder with a tx39(r3900) behind it.
-   The tx19 related options and configuration bits are handled by 
-   the tx39 flags. */
-/* end-sanitize-tx19 */
+/* Whether we should mark the file EABI64 or EABI32.  */
+static int mips_eabi64 = 0;
 
-/* Whether the processor uses hardware interlocks to protect 
+/* If they asked for mips1 or mips2 and a cpu that is
+   mips3 or greater, then mark the object file 32BITMODE.  */
+static int mips_32bitmode = 0;
+
+/* True if -mgp32 was passed.  */
+static int mips_gp32 = 0;
+
+/* True if -mfp32 was passed.  */
+static int mips_fp32 = 0;
+
+/* True if the selected ABI is defined for 32-bit registers only.  */
+static int mips_32bit_abi = 0;
+
+/* Some ISA's have delay slots for instructions which read or write
+   from a coprocessor (eg. mips1-mips3); some don't (eg mips4).
+   Return true if instructions marked INSN_LOAD_COPROC_DELAY,
+   INSN_COPROC_MOVE_DELAY, or INSN_WRITE_COND_CODE actually have a
+   delay slot in this ISA.  The uses of this macro assume that any
+   ISA that has delay slots for one of these, has them for all.  They
+   also assume that ISAs which don't have delays for these insns, don't
+   have delays for the INSN_LOAD_MEMORY_DELAY instructions either.  */
+#define ISA_HAS_COPROC_DELAYS(ISA) (        \
+   (ISA) == ISA_MIPS1                       \
+   || (ISA) == ISA_MIPS2                    \
+   || (ISA) == ISA_MIPS3                    \
+   )
+
+/*  Return true if ISA supports 64 bit gp register instructions.  */
+#define ISA_HAS_64BIT_REGS(ISA) (    \
+   (ISA) == ISA_MIPS3                \
+   || (ISA) == ISA_MIPS4             \
+   || (ISA) == ISA_MIPS5             \
+   || (ISA) == ISA_MIPS64            \
+   )
+
+#define HAVE_32BIT_GPRS                            \
+   (mips_gp32                               \
+    || mips_32bit_abi                       \
+    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+
+#define HAVE_32BIT_FPRS                     \
+   (mips_fp32                               \
+    || mips_32bit_abi                       \
+    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+
+#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
+#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
+
+#define HAVE_32BIT_ADDRESSES                \
+   (HAVE_32BIT_GPRS                         \
+    || bfd_arch_bits_per_address (stdoutput) == 32)
+
+/* Whether the processor uses hardware interlocks to protect
    reads from the HI and LO registers, and thus does not
-   require nops to be inserted.
-
-   FIXME: We really should not be checking mips_cpu here.  The -mcpu=
-   option is documented to not do anything special.  In gcc, the
-   -mcpu= option only affects scheduling, and does not affect code
-   generation.  Each test of -mcpu= here should actually be testing a
-   specific variable, such as mips_4010, and each such variable should
-   have a command line option to set it.  The -mcpu= option may be
-   used to set the default value of these options, as is the case for
-   mips_4010.  */
-
-#define hilo_interlocks (mips_4010                                  \
-                         /* start-sanitize-tx49 */                  \
-                         || mips_cpu == 4900 || mips_4900           \
-                         /* end-sanitize-tx49 */                    \
-                        /* start-sanitize-vr4320 */                \
-                        || mips_cpu == 4320                        \
-                        /* end-sanitize-vr4320 */                  \
-                        /* start-sanitize-r5900 */                 \
-                        || mips_5900                               \
-                        /* end-sanitize-r5900 */                   \
+   require nops to be inserted.  */
+
+#define hilo_interlocks (mips_arch == CPU_R4010                       \
                          )
 
 /* Whether the processor uses hardware interlocks to protect reads
    from the GPRs, and thus does not require nops to be inserted.  */
 #define gpr_interlocks \
-  (mips_opts.isa >= 2  \
-/* start-sanitize-cygnus */ \
-   || mips_5400 \
-/* end-sanitize-cygnus */ \
-/* start-sanitize-r5900 */ \
-   || mips_5900 \
-/* end-sanitize-r5900 */ \
-   || mips_3900)
+  (mips_opts.isa != ISA_MIPS1  \
+   || mips_arch == CPU_R3900)
 
 /* As with other "interlocks" this is used by hardware that has FP
    (co-processor) interlocks.  */
-/* Itbl support may require additional care here. */
-#define cop_interlocks (mips_cpu == 4300                            \
-                       /* start-sanitize-vr4320 */                 \
-                       || mips_cpu == 4320                         \
-                       /* end-sanitize-vr4320 */                   \
-                       /* start-sanitize-cygnus */                 \
-                       || mips_cpu == 5400                         \
-                       /* end-sanitize-cygnus */                   \
+/* Itbl support may require additional care here.  */
+#define cop_interlocks (mips_arch == CPU_R4300                        \
                        )
 
+/* Is this a mfhi or mflo instruction?  */
+#define MF_HILO_INSN(PINFO) \
+          ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
 /* MIPS PIC level.  */
 
 enum mips_pic_level
@@ -319,6 +320,9 @@ enum mips_pic_level
 
 static enum mips_pic_level mips_pic;
 
+/* Warn about all NOPS that the assembler generates.  */
+static int warn_nops = 0;
+
 /* 1 if we should generate 32 bit offsets from the GP register in
    SVR4_PIC mode.  Currently has no meaning in other modes.  */
 static int mips_big_got;
@@ -327,12 +331,24 @@ static int mips_big_got;
    instructions.  */
 static int mips_trap;
 
+/* 1 if double width floating point constants should not be constructed
+   by a assembling two single width halves into two single width floating
+   point registers which just happen to alias the double width destination
+   register.  On some architectures this aliasing can be disabled by a bit
+   in the status register, and the setting of this bit cannot be determined
+   automatically at assemble time.  */
+static int mips_disable_float_construction;
+
 /* Non-zero if any .set noreorder directives were used.  */
 
 static int mips_any_noreorder;
 
+/* Non-zero if nops should be inserted when the register referenced in
+   an mfhi/mflo instruction is read in the next two instructions.  */
+static int mips_7000_hilo_fix;
+
 /* The size of the small data section.  */
-static int g_switch_value = 8;
+static unsigned int g_switch_value = 8;
 /* Whether the -G option was used.  */
 static int g_switch_seen = 0;
 
@@ -345,8 +361,9 @@ static int g_switch_seen = 0;
    better.
 
    This function can only provide a guess, but it seems to work for
-   gcc output.  If it guesses wrong, the only loss should be in
-   efficiency; it shouldn't introduce any bugs.
+   gcc output.  It needs to guess right for gcc, otherwise gcc
+   will put what it thinks is a GP-relative instruction in a branch
+   delay slot.
 
    I don't know if a fix is needed for the SVR4_PIC mode.  I've only
    fixed it for the non-PIC mode.  KR 95/04/07  */
@@ -367,12 +384,12 @@ const char comment_chars[] = "#";
    .line and .file directives will appear in the pre-processed output */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
-   #NO_APP at the beginning of its output. */
+   #NO_APP at the beginning of its output.  */
 /* Also note that C style comments are always supported.  */
 const char line_comment_chars[] = "#";
 
-/* This array holds machine specific line separator characters. */
-const char line_separator_chars[] = "";
+/* This array holds machine specific line separator characters.  */
+const char line_separator_chars[] = ";";
 
 /* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
@@ -422,7 +439,7 @@ static struct mips_cl_insn prev_prev_insn;
 
 /* If we don't want information for prev_insn or prev_prev_insn, we
    point the insn_mo field at this dummy integer.  */
-static const struct mips_opcode dummy_opcode = { 0 };
+static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0 };
 
 /* Non-zero if prev_insn is valid.  */
 static int prev_insn_valid;
@@ -453,11 +470,6 @@ static int prev_insn_extended;
    noreorder.  */
 static int prev_prev_insn_unreordered;
 
-/* start-sanitize-branchbug4011 */
-/* Non-zero if the previous insn had one or more labels */
-static int prev_insn_labels;
-
-/* end-sanitize-branchbug4011 */
 /* If this is set, it points to a frag holding nop instructions which
    were inserted before the start of a noreorder section.  If those
    nops turn out to be unnecessary, the size of the frag can be
@@ -468,7 +480,7 @@ static fragS *prev_nop_frag;
 static int prev_nop_frag_holds;
 
 /* The number of nop instructions that we know we need in
-   prev_nop_frag. */
+   prev_nop_frag.  */
 static int prev_nop_frag_required;
 
 /* The number of instructions we've seen since prev_nop_frag.  */
@@ -483,7 +495,7 @@ static int prev_nop_frag_since;
 
    In order to implement this, we keep track of each unmatched HI
    relocation.  We then sort them so that they immediately precede the
-   corresponding LO relocation. */
+   corresponding LO relocation.  */
 
 struct mips_hi_fixup
 {
@@ -513,7 +525,7 @@ static const int mips32_to_16_reg_map[] =
 
 /* Map mips16 register numbers to normal MIPS register numbers.  */
 
-static const int mips16_to_32_reg_map[] =
+static const unsigned int mips16_to_32_reg_map[] =
 {
   16, 17, 2, 3, 4, 5, 6, 7
 };
@@ -589,8 +601,8 @@ static const int mips16_to_32_reg_map[] =
     | ((warn) ? 1 : 0)))
 #define RELAX_OLD(i) (((i) >> 23) & 0x7f)
 #define RELAX_NEW(i) (((i) >> 16) & 0x7f)
-#define RELAX_RELOC1(i) ((bfd_vma)(((i) >> 9) & 0x7f) - 64)
-#define RELAX_RELOC2(i) ((bfd_vma)(((i) >> 2) & 0x7f) - 64)
+#define RELAX_RELOC1(i) ((valueT) (((i) >> 9) & 0x7f) - 64)
+#define RELAX_RELOC2(i) ((valueT) (((i) >> 2) & 0x7f) - 64)
 #define RELAX_RELOC3(i) (((i) >> 1) & 1)
 #define RELAX_WARN(i) ((i) & 1)
 
@@ -633,15 +645,6 @@ static const int mips16_to_32_reg_map[] =
 #define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
 #define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
 #define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
-/* start-sanitize-branchbug4011 */
-/* The 4011 core has a bug in it's branch processing that
-   an be avoided if branches never branches (where branches
-   are defined as those starting with 'b').  We do this here
-   by insuring that labels are not directly on branch instructions,
-   and if they are inserting a no-op between the label and the
-   branch. */
-static int mips_fix_4011_branch_bug = 0;
-/* end-sanitize-branchbug4011 */
 \f
 /* Prototypes for static functions.  */
 
@@ -656,7 +659,7 @@ enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static int insn_uses_reg PARAMS ((struct mips_cl_insn *ip,
                                  unsigned int reg, enum mips_regclass class));
-static int reg_needs_delay PARAMS ((int));
+static int reg_needs_delay PARAMS ((unsigned int));
 static void mips16_mark_labels PARAMS ((void));
 static void append_insn PARAMS ((char *place,
                                 struct mips_cl_insn * ip,
@@ -682,6 +685,7 @@ static void check_absolute_expr PARAMS ((struct mips_cl_insn * ip,
                                         expressionS *));
 static void load_register PARAMS ((int *, int, expressionS *, int));
 static void load_address PARAMS ((int *counter, int reg, expressionS *ep));
+static void move_register PARAMS ((int *, int, int));
 static void macro PARAMS ((struct mips_cl_insn * ip));
 static void mips16_macro PARAMS ((struct mips_cl_insn * ip));
 #ifdef LOSING_COMPILER
@@ -720,9 +724,38 @@ static void s_mips_stab PARAMS ((int));
 static void s_mips_weakext PARAMS ((int));
 static void s_file 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 *));
 
+/* Return values of my_getSmallExpression() */
 
-static int validate_mips_insn PARAMS ((const struct mips_opcode *));
+enum
+{
+  S_EX_NONE = 0,
+  S_EX_LO,
+  S_EX_HI,
+  S_EX_HIGHER,
+  S_EX_HIGHEST,
+  S_EX_GPREL,
+  S_EX_NEG
+};
+
+/* Table and functions used to map between CPU/ISA names, and
+   ISA levels, and CPU numbers.  */
+
+struct mips_cpu_info
+{
+  const char *name;           /* CPU or ISA name.  */
+  int is_isa;                 /* Is this an ISA?  (If 0, a CPU.) */
+  int isa;                    /* ISA level.  */
+  int cpu;                    /* CPU number (default CPU if ISA).  */
+};
+
+static const struct mips_cpu_info *mips_cpu_info_from_name PARAMS ((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.
 
@@ -744,7 +777,7 @@ static int validate_mips_insn PARAMS ((const struct mips_opcode *));
 
 static const pseudo_typeS mips_pseudo_table[] =
 {
- /* MIPS specific pseudo-ops.  */
 /* MIPS specific pseudo-ops.  */
   {"option", s_option, 0},
   {"set", s_mipsset, 0},
   {"rdata", s_change_sec, 'r'},
@@ -757,7 +790,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
 
- /* Relatively generic pseudo-ops that happen to be used on MIPS
 /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
   {"asciiz", stringer, 1},
   {"bss", s_change_sec, 'b'},
@@ -766,7 +799,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"dword", s_cons, 3},
   {"weakext", s_mips_weakext, 0},
 
- /* These pseudo-ops are defined in read.c, but must be overridden
 /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
   {"align", s_align, 0},
   {"byte", s_cons, 0},
@@ -785,12 +818,18 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"stabn", s_mips_stab, 'n'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
-  { 0 },
+
+#ifdef MIPS_STABS_ELF
+  { "extern", ecoff_directive_extern, 0},
+#endif
+
+  { NULL, NULL, 0 },
 };
 
-static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
- /* These pseudo-ops should be defined by the object file format.
-    However, a.out doesn't support them, so we have versions here.  */
+static const pseudo_typeS mips_nonecoff_pseudo_table[] =
+{
+  /* These pseudo-ops should be defined by the object file format.
+     However, a.out doesn't support them, so we have versions here.  */
   {"aent", s_mips_ent, 1},
   {"bgnb", s_ignore, 0},
   {"end", s_mips_end, 0},
@@ -802,7 +841,7 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
   {"loc", s_ignore, 0},
   {"mask", s_mips_mask, 'R'},
   {"verstamp", s_ignore, 0},
-  { 0 },
+  { NULL, NULL, 0 },
 };
 
 extern void pop_insert PARAMS ((const pseudo_typeS *));
@@ -866,19 +905,59 @@ static boolean mips16_small, mips16_ext;
 static segT pdr_seg;
 #endif
 
-/*
- * 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.
- */
+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;
+}
+
+/* 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.  */
+
 void
 md_begin ()
 {
-  boolean ok = false;
   register const char *retval = NULL;
-  register unsigned int i = 0;
+  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)
@@ -889,254 +968,126 @@ md_begin ()
       cpu = a;
     }
 
-  if (mips_cpu < 0)
-    {
-      /* Set mips_cpu based on TARGET_CPU, unless TARGET_CPU is
-         just the generic 'mips', in which case set mips_cpu based
-         on the given ISA, if any. */
-
-      if (strcmp (cpu, "mips") == 0)
-        {
-          if (mips_opts.isa < 0)
-            mips_cpu = 3000;   
-
-          else if (mips_opts.isa == 2)
-            mips_cpu = 6000;
-
-          else if (mips_opts.isa == 3)
-            mips_cpu = 4000;
-
-          else if (mips_opts.isa == 4)
-            mips_cpu = 8000;
-
-          else 
-            mips_cpu = 3000;
-        }
-      
-      else if (strcmp (cpu, "r3900") == 0
-               || strcmp (cpu, "mipstx39") == 0
-               /* start-sanitize-tx19 */
-               || strcmp (cpu, "r1900") == 0
-               || strcmp (cpu, "mipstx19") == 0
-               /* end-sanitize-tx19 */
-               )
-        mips_cpu = 3900;
-
-      else if (strcmp (cpu, "r6000") == 0
-              || strcmp (cpu, "mips2") == 0)
-        mips_cpu = 6000;
-
-      else if (strcmp (cpu, "mips64") == 0
-              || strcmp (cpu, "r4000") == 0
-              || strcmp (cpu, "mips3") == 0)
-        mips_cpu = 4000;
-
-      else if (strcmp (cpu, "r4400") == 0)
-        mips_cpu = 4400;
-
-      else if (strcmp (cpu, "mips64orion") == 0
-              || strcmp (cpu, "r4600") == 0)
-        mips_cpu = 4600;
-
-      else if (strcmp (cpu, "r4650") == 0)
-        mips_cpu = 4650;
-
-      else if (strcmp (cpu, "mips64vr4300") == 0)
-        mips_cpu = 4300;
-
-      /* start-sanitize-vr4xxx */
-      else if (strcmp (cpu, "mips64vr4xxx") == 0)
-        mips_cpu = 4300;
-
-      /* end-sanitize-vr4xxx */
-      /* start-sanitize-vr4320 */
-      else if (strcmp (cpu, "r4320") == 0
-              || strcmp (cpu, "mips64vr4320") == 0)
-       mips_cpu = 4320;
-
-      /* end-sanitize-vr4320 */
-      else if (strcmp (cpu, "mips64vr4100") == 0)
-        mips_cpu = 4100;
-
-      /* start-sanitize-vr4xxx */
-      else if (strcmp (cpu, "vr4121") == 0
-              || strcmp (cpu, "mips64vr4121") == 0)
-       mips_cpu = 4121;
-
-      /* end-sanitize-vr4xxx */
-      else if (strcmp (cpu, "r4010") == 0)
-        mips_cpu = 4010;
-
-      /* start-sanitize-tx49 */
-      else if (strcmp (cpu, "mips64tx49") == 0)
-        mips_cpu = 4900;
-      /* end-sanitize-tx49 */
-
-      else if (strcmp (cpu, "r5000") == 0
-              || strcmp (cpu, "mips64vr5000") == 0)
-        mips_cpu = 5000;
-
-      /* start-sanitize-cygnus */
-      else if (strcmp (cpu, "r5400") == 0
-              || strcmp (cpu, "mips64vr5400") == 0)
-       mips_cpu = 5400;
-      /* end-sanitize-cygnus */
-
-      /* start-sanitize-r5900 */
-      else if (strcmp (cpu, "r5900") == 0
-              || strcmp (cpu, "mips64r5900") == 0)
-        mips_cpu = 5900;
-      /* end-sanitize-r5900 */
-
-      else if (strcmp (cpu, "r8000") == 0
-              || strcmp (cpu, "mips4") == 0)
-        mips_cpu = 8000;
-      
-      else if (strcmp (cpu, "r10000") == 0)
-        mips_cpu = 10000;
-
-      else if (strcmp (cpu, "mips16") == 0)
-        mips_cpu = 0; /* FIXME */
-
-      else
-        mips_cpu = 3000;
-    }
-
-  if (mips_opts.isa == -1)
-    {
-      if (mips_cpu == 3000
-          || mips_cpu == 3900)
-        mips_opts.isa = 1;
-
-      else if (mips_cpu == 6000
-               || mips_cpu == 4010)
-        mips_opts.isa = 2;
-
-      else if (mips_cpu == 4000
-               || mips_cpu == 4100
-              /* start-sanitize-vr4xxx */
-               || mips_cpu == 4111
-               || mips_cpu == 4121
-              /* end-sanitize-vr4xxx */
-               || mips_cpu == 4400
-               || mips_cpu == 4300
-               /* start-sanitize-vr4320 */
-               || mips_cpu == 4320
-               /* end-sanitize-vr4320 */
-               || mips_cpu == 4600
-               /* start-sanitize-tx49 */
-               || mips_cpu == 4900
-               /* end-sanitize-tx49 */
-               /* start-sanitize-r5900 */
-               || mips_cpu == 5900
-               /* end-sanitize-r5900 */
-               || mips_cpu == 4650)
-        mips_opts.isa = 3;
-
-      else if (mips_cpu == 5000
-               /* start-sanitize-cygnus */
-               || mips_cpu == 5400
-               /* end-sanitize-cygnus */
-               || mips_cpu == 8000
-               || mips_cpu == 10000)
-        mips_opts.isa = 4;
-      
-      else
-        mips_opts.isa = 1;
+  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)
     {
-      if (strncmp (TARGET_CPU, "mips16", sizeof "mips16" - 1) == 0)
-       mips_opts.mips16 = 1;
-      else
-       mips_opts.mips16 = 0;
+      as_fatal (_("The -mcpu option can't be used together with -march. "
+                 "Use -mtune instead of -mcpu."));
     }
 
-  if (mips_4650 < 0)
-    mips_4650 = (mips_cpu == 4650);
-
-  if (mips_4010 < 0)
-    mips_4010 = (mips_cpu == 4010);
-
-  if (mips_4100 < 0)
-    mips_4100 = (mips_cpu == 4100
-                /* start-sanitize-vr4xxx */
-                || mips_cpu == 4111
-                /* end-sanitize-vr4xxx */
-                );
-
-  /* start-sanitize-vr4xxx */
-  if (mips_4121 < 0)
-    mips_4121 = (mips_cpu == 4121);
-
-  /* end-sanitize-vr4xxx */
-  /* start-sanitize-vr4320 */
-  if (mips_4320 < 0)
-    mips_4320 = (mips_cpu == 4320);
-
-  /* end-sanitize-vr4320 */
-  /* start-sanitize-cygnus */
-  if (mips_5400 < 0)
-    mips_5400 = (mips_cpu == 5400);
-  /* end-sanitize-cygnus */
+  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."));
+    }
 
-  /* start-sanitize-r5900 */
-  if (mips_5900 < 0)
-    mips_5900 = (mips_cpu == 5900);
-  /* end-sanitize-r5900 */
+  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."));
+    }
 
-  if (mips_3900 < 0)
-    mips_3900 = (mips_cpu == 3900);
+  /* 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;
+       }
+    }
+  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;
+    }
 
-  /* start-sanitize-tx49 */
-  if (mips_4900 < 0)
-    mips_4900 = (mips_cpu == 4900);
+  if (mips_tune == CPU_UNKNOWN)
+    mips_tune = mips_arch;
 
-  /* end-sanitize-tx49 */
+  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. */
+     if necessary.  */
   cpu = NULL;
   if (a != NULL)
     {
-    free (a);
-    a = NULL;
+      free (a);
+      a = NULL;
     }
 
-  if (mips_opts.isa < 2 && mips_trap)
+  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 (mips_opts.isa > 2 && 0 == strcmp (mips_abi_string,"eabi"))
+     the best, but then neither is basing the abi on the isa.  */
+  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
+      && mips_abi_string
+      && 0 == strcmp (mips_abi_string, "eabi"))
     mips_eabi64 = 1;
 
-  if (mips_cpu != 0 && mips_cpu != -1)
-    {
-      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_cpu);
-    }
-  else
-    {
-      switch (mips_opts.isa)
-       {
-       case 1:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 3000);
-         break;
-       case 2:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 6000);
-         break;
-       case 3:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 4000);
-         break;
-       case 4:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 8000);
-         break;
-       }
-    }
+  /* 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 (! ok)
+  if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
   file_mips_isa = mips_opts.isa;
@@ -1270,10 +1221,9 @@ md_begin ()
          {
            sec = subseg_new (".reginfo", (subsegT) 0);
 
-
            (void) bfd_set_section_flags (stdoutput, sec, flags);
            (void) bfd_set_section_alignment (stdoutput, sec, 2);
-       
+
 #ifdef OBJ_ELF
            mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
 #endif
@@ -1353,8 +1303,8 @@ md_assemble (str)
   else
     {
       mips_ip (str, &insn);
-      DBG((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"), 
-               str, insn.insn_opcode));
+      DBG ((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"),
+           str, insn.insn_opcode));
     }
 
   if (insn_error)
@@ -1467,13 +1417,13 @@ insn_uses_reg (ip, reg, class)
 
 static int
 reg_needs_delay (reg)
-     int reg;
+     unsigned int reg;
 {
   unsigned long prev_pinfo;
 
   prev_pinfo = prev_insn.insn_mo->pinfo;
   if (! mips_opts.noreorder
-      && mips_opts.isa < 4
+      && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
       && ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
          || (! gpr_interlocks
              && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))))
@@ -1482,7 +1432,7 @@ reg_needs_delay (reg)
         delays delay the use of general register rt for one
         instruction on the r3000.  The r6000 and r4000 use
         interlocks.  */
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       know (prev_pinfo & INSN_WRITE_GPR_T);
       if (reg == ((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT))
        return 1;
@@ -1505,6 +1455,7 @@ mips16_mark_labels ()
   if (mips_opts.mips16)
     {
       struct insn_label_list *l;
+      valueT val;
 
       for (l = insn_labels; l != NULL; l = l->next)
        {
@@ -1512,8 +1463,9 @@ mips16_mark_labels ()
          if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
            S_SET_OTHER (l->label, STO_MIPS16);
 #endif
-         if ((l->label->sy_value.X_add_number & 1) == 0)
-           ++l->label->sy_value.X_add_number;
+         val = S_GET_VALUE (l->label);
+         if ((val & 1) == 0)
+           S_SET_VALUE (l->label, val + 1);
        }
     }
 }
@@ -1535,10 +1487,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
   char *f;
   fixS *fixp;
   int nops = 0;
-  /* start-sanitize-branchbug4011 */
-  int label_nop = 0;          /* True if a no-op needs to appear between
-                                the current insn and the current labels */
-  /* end-sanitize-branchbug4011 */
 
   /* Mark instruction labels in mips16 mode.  */
   if (mips_opts.mips16)
@@ -1580,7 +1528,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       /* The previous insn might require a delay slot, depending upon
         the contents of the current insn.  */
       if (! mips_opts.mips16
-         && mips_opts.isa < 4
+         && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
          && (((prev_pinfo & INSN_LOAD_COPROC_DELAY)
                && ! cop_interlocks)
              || (! gpr_interlocks
@@ -1590,7 +1538,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             delays delay the use of general register rt for one
             instruction on the r3000.  The r6000 and r4000 use
             interlocks.  */
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          know (prev_pinfo & INSN_WRITE_GPR_T);
          if (mips_optimize == 0
              || insn_uses_reg (ip,
@@ -1600,10 +1548,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
            ++nops;
        }
       else if (! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (((prev_pinfo & INSN_COPROC_MOVE_DELAY)
-                    && ! cop_interlocks)
-                  || (mips_opts.isa < 2
+                   && ! cop_interlocks)
+                  || (mips_opts.isa == ISA_MIPS1
                       && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))))
        {
          /* A generic coprocessor delay.  The previous instruction
@@ -1621,7 +1569,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             than the floating point unit are not distinguished at
             all.  */
           /* Itbl support may require additional care here. FIXME!
-             Need to modify this to include knowledge about 
+             Need to modify this to include knowledge about
              user specified delays!  */
          if (prev_pinfo & INSN_WRITE_FPR_T)
            {
@@ -1649,7 +1597,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 instruction may set the condition codes, and the
                 current instruction uses them, we must insert two
                 NOPS.  */
-              /* Itbl support may require additional care here. */
+              /* Itbl support may require additional care here.  */
              if (mips_optimize == 0
                  || ((prev_pinfo & INSN_WRITE_COND_CODE)
                      && (pinfo & INSN_READ_COND_CODE)))
@@ -1659,7 +1607,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
            }
        }
       else if (! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (prev_pinfo & INSN_WRITE_COND_CODE)
                && ! cop_interlocks)
        {
@@ -1668,42 +1616,92 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             (this means it is a floating point comparison
             instruction).  If this instruction uses the condition
             codes, we need to insert a single NOP.  */
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          if (mips_optimize == 0
              || (pinfo & INSN_READ_COND_CODE))
            ++nops;
        }
+
+      /* If we're fixing up mfhi/mflo for the r7000 and the
+        previous insn was an mfhi/mflo and the current insn
+        reads the register that the mfhi/mflo wrote to, then
+        insert two nops.  */
+
+      else if (mips_7000_hilo_fix
+              && MF_HILO_INSN (prev_pinfo)
+              && insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
+                                     & OP_MASK_RD),
+                                MIPS_GR_REG))
+       {
+         nops += 2;
+       }
+
+      /* If we're fixing up mfhi/mflo for the r7000 and the
+        2nd previous insn was an mfhi/mflo and the current insn
+        reads the register that the mfhi/mflo wrote to, then
+        insert one nop.  */
+
+      else if (mips_7000_hilo_fix
+              && MF_HILO_INSN (prev_prev_insn.insn_opcode)
+              && insn_uses_reg (ip, ((prev_prev_insn.insn_opcode >> OP_SH_RD)
+                                       & OP_MASK_RD),
+                                    MIPS_GR_REG))
+
+       {
+         nops += 1;
+       }
+
       else if (prev_pinfo & INSN_READ_LO)
        {
          /* The previous instruction reads the LO register; if the
             current instruction writes to the LO register, we must
-            insert two NOPS.  Some newer processors have interlocks. 
-            Also the tx39's multiply instructions can be exectuted 
+            insert two NOPS.  Some newer processors have interlocks.
+            Also the tx39's multiply instructions can be exectuted
              immediatly after a read from HI/LO (without the delay),
-             though the tx39's divide insns still do require the 
-            delay. */
+             though the tx39's divide insns still do require the
+            delay.  */
          if (! (hilo_interlocks
-                || (mips_3900 && (pinfo & INSN_MULT)))
+                || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_LO)))
            nops += 2;
+         /* Most mips16 branch insns don't have a delay slot.
+            If a read from LO is immediately followed by a branch
+            to a write to LO we have a read followed by a write
+            less than 2 insns away.  We assume the target of
+            a branch might be a write to LO, and insert a nop
+            between a read and an immediately following branch.  */
+         else if (mips_opts.mips16
+                  && (mips_optimize == 0
+                      || (pinfo & MIPS16_INSN_BRANCH)))
+           nops += 1;
        }
       else if (prev_insn.insn_mo->pinfo & INSN_READ_HI)
        {
          /* The previous instruction reads the HI register; if the
             current instruction writes to the HI register, we must
             insert a NOP.  Some newer processors have interlocks.
-            Also the note tx39's multiply above. */
+            Also the note tx39's multiply above.  */
          if (! (hilo_interlocks
-                || (mips_3900 && (pinfo & INSN_MULT)))
+                || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_HI)))
            nops += 2;
+         /* Most mips16 branch insns don't have a delay slot.
+            If a read from HI is immediately followed by a branch
+            to a write to HI we have a read followed by a write
+            less than 2 insns away.  We assume the target of
+            a branch might be a write to HI, and insert a nop
+            between a read and an immediately following branch.  */
+         else if (mips_opts.mips16
+                  && (mips_optimize == 0
+                      || (pinfo & MIPS16_INSN_BRANCH)))
+           nops += 1;
        }
 
       /* If the previous instruction was in a noreorder section, then
          we don't want to insert the nop after all.  */
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       if (prev_insn_unreordered)
        nops = 0;
 
@@ -1716,7 +1714,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
         instruction, we must check for these cases compared to the
         instruction previous to the previous instruction.  */
       if ((! mips_opts.mips16
-          && mips_opts.isa < 4
+          && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
           && (prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
           && (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
           && (pinfo & INSN_READ_COND_CODE)
@@ -1724,11 +1722,11 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
              && (pinfo & INSN_WRITE_LO)
              && ! (hilo_interlocks
-                   || (mips_3900 && (pinfo & INSN_MULT))))
+                   || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT))))
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
              && (pinfo & INSN_WRITE_HI)
              && ! (hilo_interlocks
-                   || (mips_3900 && (pinfo & INSN_MULT)))))
+                   || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))))
        prev_prev_nop = 1;
       else
        prev_prev_nop = 0;
@@ -1745,28 +1743,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
         to 0.  */
       if (nops > 0
          && ! mips_opts.noreorder
-         && ip->insn_opcode == (mips_opts.mips16 ? 0x6500 : 0))
+         && ip->insn_opcode == (unsigned) (mips_opts.mips16 ? 0x6500 : 0))
        --nops;
 
-      /* start-sanitize-branchbug4011 */
-      /* If we have a label on a branch insn, we need at least one no-op
-        between the label and the branch.  The pinfo flags in this test
-        must cover all the kinds of branches.  */
-      if (mips_fix_4011_branch_bug
-         && insn_labels != NULL
-         && (ip->insn_mo->pinfo 
-             & (INSN_UNCOND_BRANCH_DELAY
-                |INSN_COND_BRANCH_DELAY
-                |INSN_COND_BRANCH_LIKELY)))
-       {
-         label_nop = 1;
-         
-         /* Make sure we've got at least one nop. */
-         if (nops == 0) 
-           nops = 1;
-       }
-
-      /* end-sanitize-branchbug4011 */
       /* Now emit the right number of NOP instructions.  */
       if (nops > 0 && ! mips_opts.noreorder)
        {
@@ -1778,12 +1757,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          old_frag = frag_now;
          old_frag_offset = frag_now_fix ();
 
-         /* start-sanitize-branchbug4011 */
-         /* Emit the nops that should be before the label. */
-         if (label_nop)
-           nops -= 1;
-
-         /* end-sanitize-branchbug4011 */
          for (i = 0; i < nops; i++)
            emit_nop ();
 
@@ -1803,34 +1776,28 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
          for (l = insn_labels; l != NULL; l = l->next)
            {
+             valueT val;
+
              assert (S_GET_SEGMENT (l->label) == now_seg);
-             l->label->sy_frag = frag_now;
-             S_SET_VALUE (l->label, (valueT) frag_now_fix ());
+             symbol_set_frag (l->label, frag_now);
+             val = (valueT) frag_now_fix ();
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               ++l->label->sy_value.X_add_number;
+               val += 1;
+             S_SET_VALUE (l->label, val);
            }
 
 #ifndef NO_ECOFF_DEBUGGING
          if (ECOFF_DEBUGGING)
            ecoff_fix_loc (old_frag, old_frag_offset);
 #endif
-         /* start-sanitize-branchbug4011 */
-         if (label_nop)
-           {
-             /* Emit the nop after the label, and return the
-                nop count to it's proper value. */
-             emit_nop ();
-             nops += 1;
-           }
-         /* end-sanitize-branchbug4011 */
        }
       else if (prev_nop_frag != NULL)
        {
          /* We have a frag holding nops we may be able to remove.  If
              we don't need any nops, we can decrease the size of
              prev_nop_frag by the size of one instruction.  If we do
-             need some nops, we count them in prev_nops_required. */
+             need some nops, we count them in prev_nops_required.  */
          if (prev_nop_frag_since == 0)
            {
              if (nops == 0)
@@ -1931,12 +1898,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 | ((address_expr->X_add_number & 0x3fffc) >> 2));
              break;
 
-           /* start-sanitize-r5900 */
-           case BFD_RELOC_MIPS15_S3:
-             ip->insn_opcode |= ((imm_expr.X_add_number & 0x7fff) >> 3) << 6;
-             break;
-           /* end-sanitize-r5900 */
-
            case BFD_RELOC_16_PCREL_S2:
              goto need_reloc;
 
@@ -2009,13 +1970,13 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
        mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FR) & OP_MASK_FR);
       if (pinfo & INSN_COP)
        {
-         /* We don't keep enough information to sort these cases out. 
-            The itbl support does keep this information however, although 
-            we currently don't support itbl fprmats as part of the cop 
-            instruction.  May want to add this support in the future. */
+         /* We don't keep enough information to sort these cases out.
+            The itbl support does keep this information however, although
+            we currently don't support itbl fprmats as part of the cop
+            instruction.  May want to add this support in the future.  */
        }
       /* Never set the bit for $0, which is always zero.  */
-      mips_gprmask &=1 << 0;
+      mips_gprmask &= ~1 << 0;
     }
   else
     {
@@ -2062,15 +2023,11 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 already know we can not swap.  */
              || nops != 0
              /* If we don't even know the previous insn, we can not
-                swap. */
+                swap.  */
              || ! prev_insn_valid
              /* If the previous insn is already in a branch delay
                 slot, then we can not swap.  */
              || prev_insn_is_delay_slot
-             /* start-sanitize-branchbug4011 */
-             /* We can't swap the branch back to a previous label */
-             || (mips_fix_4011_branch_bug && prev_insn_labels)
-             /* end-sanitize-branchbug4011 */
              /* If the previous previous insn was in a .set
                 noreorder, we can't swap.  Actually, the MIPS
                 assembler will swap in this situation.  However, gcc
@@ -2109,19 +2066,20 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 we can not swap, and I don't feel like handling that
                 case.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                  && (pinfo & INSN_READ_COND_CODE))
              /* We can not swap with an instruction that requires a
                 delay slot, becase the target of the branch might
                 interfere with that instruction.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                  && (prev_pinfo
-              /* Itbl support may require additional care here. */
+              /* Itbl support may require additional care here.  */
                      & (INSN_LOAD_COPROC_DELAY
                         | INSN_COPROC_MOVE_DELAY
                         | INSN_WRITE_COND_CODE)))
-             || (! (hilo_interlocks || (mips_3900 && (pinfo & INSN_MULT)))
+             || (! (hilo_interlocks
+                    || (mips_tune == CPU_R3900 && (pinfo & INSN_MULT)))
                  && (prev_pinfo
                      & (INSN_READ_LO
                         | INSN_READ_HI)))
@@ -2129,8 +2087,8 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  && ! gpr_interlocks
                  && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))
              || (! mips_opts.mips16
-                 && mips_opts.isa < 2
-                  /* Itbl support may require additional care here. */
+                 && mips_opts.isa == ISA_MIPS1
+                  /* Itbl support may require additional care here.  */
                  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))
              /* We can not swap with a branch instruction.  */
              || (prev_pinfo
@@ -2234,8 +2192,8 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 delay, and sets a register that the branch reads, we
                 can not swap.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
-              /* Itbl support may require additional care here. */
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
+              /* Itbl support may require additional care here.  */
                  && ((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
                      || (! gpr_interlocks
                          && (prev_prev_insn.insn_mo->pinfo
@@ -2261,9 +2219,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  mode, we can not swap.  This normally means that the
                  previous instruction was a 4 byte branch anyhow.  */
              || (mips_opts.mips16 && prev_insn_fixp)
-             /* If the previous instruction is a sync, sync.l, or 
-                sync.p, we can not swap. */
-             || (prev_pinfo && INSN_SYNC))
+             /* If the previous instruction is a sync, sync.l, or
+                sync.p, we can not swap.  */
+             || (prev_pinfo & INSN_SYNC))
            {
              /* We could do even better for unconditional branches to
                 portions of this object file; we could pick up the
@@ -2381,9 +2339,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       prev_insn_frag = frag_now;
       prev_insn_where = f - frag_now->fr_literal;
       prev_insn_valid = 1;
-      /* start-sanitize-branchbug4011 */
-      prev_insn_labels = !! insn_labels;
-      /* end-sanitize-branchbug4011 */
     }
   else if (place == NULL)
     {
@@ -2395,9 +2350,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       prev_insn_reloc_type = reloc_type;
       prev_prev_insn_unreordered = prev_insn_unreordered;
       prev_insn_unreordered = 1;
-      /* start-sanitize-branchbug4011 */
-      prev_insn_labels = !! insn_labels;
-      /* end-sanitize-branchbug4011 */
     }
 
   /* We just output an insn, so the next one doesn't have a label.  */
@@ -2416,7 +2368,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
 /* This function forgets that there was any previous instruction or
    label.  If PRESERVE is non-zero, it remembers enough information to
-   know whether nops are needed before a noreorder section. */
+   know whether nops are needed before a noreorder section.  */
 
 static void
 mips_no_prev_insn (preserve)
@@ -2435,9 +2387,6 @@ mips_no_prev_insn (preserve)
   prev_insn_is_delay_slot = 0;
   prev_insn_unreordered = 0;
   prev_insn_extended = 0;
-  /* start-sanitize-branchbug4011 */
-  prev_insn_labels = 0;
-  /* end-sanitize-branchbug4011 */
   prev_insn_reloc_type = BFD_RELOC_UNUSED;
   prev_prev_insn_unreordered = 0;
   mips_clear_insn_labels ();
@@ -2447,7 +2396,7 @@ mips_no_prev_insn (preserve)
    something other than instructions.  It inserts any NOPS which might
    be needed by the previous instruction, and clears the information
    kept for the previous instructions.  The INSNS parameter is true if
-   instructions are to follow. */
+   instructions are to follow.  */
 
 static void
 mips_emit_delays (insns)
@@ -2459,7 +2408,7 @@ mips_emit_delays (insns)
 
       nops = 0;
       if ((! mips_opts.mips16
-          && mips_opts.isa < 4
+          && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
           && (! cop_interlocks
                && (prev_insn.insn_mo->pinfo
                    & (INSN_LOAD_COPROC_DELAY
@@ -2471,17 +2420,17 @@ mips_emit_delays (insns)
                     | INSN_READ_HI)))
          || (! mips_opts.mips16
              && ! gpr_interlocks
-             && (prev_insn.insn_mo->pinfo 
+             && (prev_insn.insn_mo->pinfo
                   & INSN_LOAD_MEMORY_DELAY))
          || (! mips_opts.mips16
-             && mips_opts.isa < 2
+             && mips_opts.isa == ISA_MIPS1
              && (prev_insn.insn_mo->pinfo
                  & INSN_COPROC_MEMORY_DELAY)))
        {
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          ++nops;
          if ((! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (! cop_interlocks
                    && prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
              || (! hilo_interlocks
@@ -2493,14 +2442,14 @@ mips_emit_delays (insns)
            nops = 0;
        }
       else if ((! mips_opts.mips16
-               && mips_opts.isa < 4
+               && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                && (! cop_interlocks
                     && prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
               || (! hilo_interlocks
                   && ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
                       || (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
        {
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          if (! prev_prev_insn_unreordered)
            ++nops;
        }
@@ -2526,19 +2475,22 @@ mips_emit_delays (insns)
          if (insns)
            {
              /* Move on to a new frag, so that it is safe to simply
-                 decrease the size of prev_nop_frag. */
+                 decrease the size of prev_nop_frag.  */
              frag_wane (frag_now);
              frag_new (0);
            }
 
          for (l = insn_labels; l != NULL; l = l->next)
            {
+             valueT val;
+
              assert (S_GET_SEGMENT (l->label) == now_seg);
-             l->label->sy_frag = frag_now;
-             S_SET_VALUE (l->label, (valueT) frag_now_fix ());
+             symbol_set_frag (l->label, frag_now);
+             val = (valueT) frag_now_fix ();
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               ++l->label->sy_value.X_add_number;
+               val += 1;
+             S_SET_VALUE (l->label, val);
            }
        }
     }
@@ -2577,7 +2529,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   struct mips_cl_insn insn;
   bfd_reloc_code_real_type r;
   va_list args;
-  int insn_isa;
 
 #ifdef USE_STDARG
   va_start (args, fmt);
@@ -2611,52 +2562,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   /* Search until we get a match for NAME.  */
   while (1)
     {
-      if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-      else
-       insn_isa = 15;
-
       if (strcmp (fmt, insn.insn_mo->args) == 0
          && insn.insn_mo->pinfo != INSN_MACRO
-         && (insn_isa <= mips_opts.isa
-             || (mips_4650
-                 && (insn.insn_mo->membership & INSN_4650) != 0)
-             || (mips_4010
-                 && (insn.insn_mo->membership & INSN_4010) != 0)
-             || (mips_4100
-                 && (insn.insn_mo->membership & INSN_4100) != 0)
-             /* start-sanitize-vr4xxx */
-             || (mips_4121
-                 && (insn.insn_mo->membership & INSN_4121) != 0)
-             /* end-sanitize-vr4xxx */
-             /* start-sanitize-vr4320 */
-             || (mips_4320
-                 && (insn.insn_mo->membership & INSN_4320) != 0)
-             /* end-sanitize-vr4320 */
-             /* start-sanitize-tx49 */
-             || (mips_4900
-                 && (insn.insn_mo->membership & INSN_4900) != 0)
-             /* end-sanitize-tx49 */
-             /* start-sanitize-r5900 */
-             || (mips_5900
-                 && (insn.insn_mo->membership & INSN_5900) != 0)
-             /* end-sanitize-r5900 */
-             /* start-sanitize-cygnus */
-             || (mips_5400
-                 && (insn.insn_mo->membership & INSN_5400) != 0)
-             /* end-sanitize-cygnus */
-             || (mips_3900
-                 && (insn.insn_mo->membership & INSN_3900) != 0))
-         /* start-sanitize-r5900 */
-         && (! mips_5900 || (insn.insn_mo->pinfo & FP_D) == 0)
-         /* end-sanitize-r5900 */
-         && (! mips_4650 || (insn.insn_mo->pinfo & FP_D) == 0))
+         && OPCODE_IS_MEMBER (insn.insn_mo, mips_opts.isa, mips_arch)
+         && (mips_arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
        break;
 
       ++insn.insn_mo;
@@ -2680,49 +2589,65 @@ macro_build (place, counter, ep, name, fmt, va_alist)
        case 't':
        case 'w':
        case 'E':
-         insn.insn_opcode |= va_arg (args, int) << 16;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_RT;
          continue;
 
        case 'c':
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE;
+         continue;
+
        case 'T':
        case 'W':
-         insn.insn_opcode |= va_arg (args, int) << 16;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_FT;
          continue;
 
        case 'd':
        case 'G':
-         insn.insn_opcode |= va_arg (args, int) << 11;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_RD;
          continue;
 
+       case 'U':
+         {
+           int tmp = va_arg (args, int);
+
+           insn.insn_opcode |= tmp << OP_SH_RT;
+           insn.insn_opcode |= tmp << OP_SH_RD;
+           continue;
+         }
+
        case 'V':
        case 'S':
-         insn.insn_opcode |= va_arg (args, int) << 11;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_FS;
          continue;
 
        case 'z':
          continue;
 
        case '<':
-         insn.insn_opcode |= va_arg (args, int) << 6;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_SHAMT;
          continue;
 
        case 'D':
-         insn.insn_opcode |= va_arg (args, int) << 6;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_FD;
          continue;
 
        case 'B':
-         insn.insn_opcode |= va_arg (args, int) << 6;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE20;
+         continue;
+
+       case 'J':
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE19;
          continue;
 
        case 'q':
-         insn.insn_opcode |= va_arg (args, int) << 6;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE2;
          continue;
 
        case 'b':
        case 's':
        case 'r':
        case 'v':
-         insn.insn_opcode |= va_arg (args, int) << 21;
+         insn.insn_opcode |= va_arg (args, int) << OP_SH_RS;
          continue;
 
        case 'i':
@@ -2737,7 +2662,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
                  || r == BFD_RELOC_MIPS_GOT_LO16
                  || r == BFD_RELOC_MIPS_CALL_LO16
                  || (ep->X_op == O_subtract
-                     && now_seg == text_section
                      && r == BFD_RELOC_PCREL_LO16));
          continue;
 
@@ -2751,7 +2675,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
                              || r == BFD_RELOC_MIPS_GOT_HI16
                              || r == BFD_RELOC_MIPS_CALL_HI16))
                      || (ep->X_op == O_subtract
-                         && now_seg == text_section
                          && r == BFD_RELOC_PCREL_HI16_S)));
          if (ep->X_op == O_constant)
            {
@@ -2802,7 +2725,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
 static void
 mips16_macro_build (place, counter, ep, name, fmt, args)
      char *place;
-     int *counter;
+     int *counter ATTRIBUTE_UNUSED;
      expressionS *ep;
      const char *name;
      const char *fmt;
@@ -2954,10 +2877,8 @@ macro_build_lui (place, counter, ep, regnum)
   if (high_expr.X_op == O_constant)
     {
       /* we can compute the instruction now without a relocation entry */
-      if (high_expr.X_add_number & 0x8000)
-       high_expr.X_add_number += 0x10000;
-      high_expr.X_add_number =
-       ((unsigned long) high_expr.X_add_number >> 16) & 0xffff;
+      high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
+                               >> 16) & 0xffff;
       r = BFD_RELOC_UNUSED;
     }
   else
@@ -3155,9 +3076,9 @@ load_register (counter, reg, ep, dbl)
                    || ! ep->X_unsigned
                    || sizeof (ep->X_add_number) > 4
                    || (ep->X_add_number & 0x80000000) == 0))
-              || ((mips_opts.isa < 3 || ! dbl)
+              || ((HAVE_32BIT_GPRS || ! dbl)
                   && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0)
-              || (mips_opts.isa < 3
+              || (HAVE_32BIT_GPRS
                   && ! dbl
                   && ((ep->X_add_number &~ (offsetT) 0xffffffff)
                       == ~ (offsetT) 0xffffffff)))
@@ -3174,7 +3095,7 @@ load_register (counter, reg, ep, dbl)
 
   /* The value is larger than 32 bits.  */
 
-  if (mips_opts.isa < 3)
+  if (HAVE_32BIT_GPRS)
     {
       as_bad (_("Number larger than 32 bits"));
       macro_build ((char *) NULL, counter, ep, "addiu", "t,r,j", reg, 0,
@@ -3212,63 +3133,65 @@ load_register (counter, reg, ep, dbl)
       unsigned long hi, lo;
 
       if (hi32.X_add_number == 0xffffffff)
-        {
-          if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
-            {
-              macro_build ((char *) NULL, counter, &lo32, "addiu", "t,r,j",
+       {
+         if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
+           {
+             macro_build ((char *) NULL, counter, &lo32, "addiu", "t,r,j",
                           reg, 0, (int) BFD_RELOC_LO16);
-              return;
-            }
-          if (lo32.X_add_number & 0x80000000)
-            {
-              macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
-                           (int) BFD_RELOC_HI16);
+             return;
+           }
+         if (lo32.X_add_number & 0x80000000)
+           {
+             macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
+                          (int) BFD_RELOC_HI16);
              if (lo32.X_add_number & 0xffff)
                macro_build ((char *) NULL, counter, &lo32, "ori", "t,r,i",
                             reg, reg, (int) BFD_RELOC_LO16);
-              return;
-            }
-        }
+             return;
+           }
+       }
 
       /* Check for 16bit shifted constant.  We know that hi32 is
          non-zero, so start the mask on the first bit of the hi32
          value.  */
       shift = 17;
       do
-       {
-        unsigned long himask, lomask;
-
-        if (shift < 32)
-          {
-            himask = 0xffff >> (32 - shift);
-            lomask = (0xffff << shift) & 0xffffffff;
-          }
-        else
-          {
-            himask = 0xffff << (shift - 32);
-            lomask = 0;
-          }
-        if ((hi32.X_add_number & ~ (offsetT) himask) == 0
-            && (lo32.X_add_number & ~ (offsetT) lomask) == 0)
-          {
-            expressionS tmp;
-
-            tmp.X_op = O_constant;
-            if (shift < 32)
-              tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
-                                  | (lo32.X_add_number >> shift));
-            else
-              tmp.X_add_number = hi32.X_add_number >> (shift - 32);
-            macro_build ((char *) NULL, counter, &tmp, "ori", "t,r,i", reg, 0,
-                         (int) BFD_RELOC_LO16);
-            macro_build ((char *) NULL, counter, NULL,
-                         (shift >= 32) ? "dsll32" : "dsll",
-                         "d,w,<", reg, reg,
-                         (shift >= 32) ? shift - 32 : shift);
-            return;
-          }
-         shift++;
-       } while (shift <= (64 - 16));
+       {
+         unsigned long himask, lomask;
+
+         if (shift < 32)
+           {
+             himask = 0xffff >> (32 - shift);
+             lomask = (0xffff << shift) & 0xffffffff;
+           }
+         else
+           {
+             himask = 0xffff << (shift - 32);
+             lomask = 0;
+           }
+         if ((hi32.X_add_number & ~(offsetT) himask) == 0
+             && (lo32.X_add_number & ~(offsetT) lomask) == 0)
+           {
+             expressionS tmp;
+
+             tmp.X_op = O_constant;
+             if (shift < 32)
+               tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
+                                   | (lo32.X_add_number >> shift));
+             else
+               tmp.X_add_number = hi32.X_add_number >> (shift - 32);
+             macro_build ((char *) NULL, counter, &tmp,
+                          "ori", "t,r,i", reg, 0,
+                          (int) BFD_RELOC_LO16);
+             macro_build ((char *) NULL, counter, NULL,
+                          (shift >= 32) ? "dsll32" : "dsll",
+                          "d,w,<", reg, reg,
+                          (shift >= 32) ? shift - 32 : shift);
+             return;
+           }
+         shift++;
+       }
+      while (shift <= (64 - 16));
 
       /* Find the bit number of the lowest one bit, and store the
          shifted value in hi/lo.  */
@@ -3300,38 +3223,38 @@ load_register (counter, reg, ep, dbl)
       /* Optimize if the shifted value is a (power of 2) - 1.  */
       if ((hi == 0 && ((lo + 1) & lo) == 0)
          || (lo == 0xffffffff && ((hi + 1) & hi) == 0))
-        {
-          shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
+       {
+         shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
          if (shift != 0)
-            {
+           {
              expressionS tmp;
 
              /* This instruction will set the register to be all
                  ones.  */
-              tmp.X_op = O_constant;
-              tmp.X_add_number = (offsetT) -1;
-              macro_build ((char *) NULL, counter, &tmp, "addiu", "t,r,j",
+             tmp.X_op = O_constant;
+             tmp.X_add_number = (offsetT) -1;
+             macro_build ((char *) NULL, counter, &tmp, "addiu", "t,r,j",
                           reg, 0, (int) BFD_RELOC_LO16);
-              if (bit != 0)
-                {
-                  bit += shift;
-                  macro_build ((char *) NULL, counter, NULL,
-                               (bit >= 32) ? "dsll32" : "dsll",
-                               "d,w,<", reg, reg,
-                               (bit >= 32) ? bit - 32 : bit);
-                }
-              macro_build ((char *) NULL, counter, NULL,
+             if (bit != 0)
+               {
+                 bit += shift;
+                 macro_build ((char *) NULL, counter, NULL,
+                              (bit >= 32) ? "dsll32" : "dsll",
+                              "d,w,<", reg, reg,
+                              (bit >= 32) ? bit - 32 : bit);
+               }
+             macro_build ((char *) NULL, counter, NULL,
                           (shift >= 32) ? "dsrl32" : "dsrl",
-                           "d,w,<", reg, reg,
+                          "d,w,<", reg, reg,
                           (shift >= 32) ? shift - 32 : shift);
-              return;
-            }
-        }
+             return;
+           }
+       }
 
       /* Sign extend hi32 before calling load_register, because we can
          generally get better code when we load a sign extended value.  */
       if ((hi32.X_add_number & 0x80000000) != 0)
-       hi32.X_add_number |= ~ (offsetT) 0xffffffff;
+       hi32.X_add_number |= ~(offsetT) 0xffffffff;
       load_register (counter, reg, &hi32, 0);
       freg = reg;
     }
@@ -3349,13 +3272,13 @@ load_register (counter, reg, ep, dbl)
       expressionS mid16;
 
       if ((freg == 0) && (lo32.X_add_number == 0xffffffff))
-        {
+       {
          macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
                       (int) BFD_RELOC_HI16);
-          macro_build ((char *) NULL, counter, NULL, "dsrl32", "d,w,<", reg,
-                       reg, 0);
-          return;
-        }
+         macro_build ((char *) NULL, counter, NULL, "dsrl32", "d,w,<", reg,
+                      reg, 0);
+         return;
+       }
 
       if (freg != 0)
        {
@@ -3407,16 +3330,14 @@ load_address (counter, reg, ep)
           lui          $reg,<sym>              (BFD_RELOC_HI16_S)
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
         If we have an addend, we always use the latter form.  */
-      if ((valueT) ep->X_add_number >= MAX_GPREL_OFFSET
-          || nopic_need_relax (ep->X_add_symbol, 1))
+      if ((valueT) ep->X_add_number > MAX_GPREL_OFFSET
+         || nopic_need_relax (ep->X_add_symbol, 1))
        p = NULL;
       else
        {
          frag_grow (20);
          macro_build ((char *) NULL, counter, ep,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
          p = frag_var (rs_machine_dependent, 8, 0,
                        RELAX_ENCODE (4, 8, 0, 4, 0,
@@ -3427,9 +3348,7 @@ load_address (counter, reg, ep)
       if (p != NULL)
        p += 4;
       macro_build (p, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa < 3)
-                   ? "addiu" : "daddiu"),
+                  HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
     }
   else if (mips_pic == SVR4_PIC && ! mips_big_got)
@@ -3447,18 +3366,14 @@ load_address (counter, reg, ep)
       ep->X_add_number = 0;
       frag_grow (20);
       macro_build ((char *) NULL, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "lw" : "ld"),
+                  HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
       macro_build ((char *) NULL, counter, (expressionS *) NULL, "nop", "");
       p = frag_var (rs_machine_dependent, 4, 0,
                    RELAX_ENCODE (0, 4, -8, 0, 0, mips_opts.warn_about_macros),
                    ep->X_add_symbol, (offsetT) 0, (char *) NULL);
       macro_build (p, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "addiu" : "daddiu"),
+                  HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
       if (ex.X_add_number != 0)
        {
@@ -3466,9 +3381,7 @@ load_address (counter, reg, ep)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          ex.X_op = O_constant;
          macro_build ((char *) NULL, counter, &ex,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa  < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
@@ -3497,14 +3410,10 @@ load_address (counter, reg, ep)
       macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
                   (int) BFD_RELOC_MIPS_GOT_HI16);
       macro_build ((char *) NULL, counter, (expressionS *) NULL,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "addu" : "daddu"),
+                  HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                   "d,v,t", reg, reg, GP);
       macro_build ((char *) NULL, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "lw" : "ld"),
+                  HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT_LO16, reg);
       p = frag_var (rs_machine_dependent, 12 + off, 0,
                    RELAX_ENCODE (12, 12 + off, off, 8 + off, 0,
@@ -3519,18 +3428,12 @@ load_address (counter, reg, ep)
          macro_build (p, counter, (expressionS *) NULL, "nop", "");
          p += 4;
        }
-      macro_build (p, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "lw" : "ld"),
+      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
       p += 4;
       macro_build (p, counter, (expressionS *) NULL, "nop", "");
       p += 4;
-      macro_build (p, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "addiu" : "daddiu"),
+      macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
       if (ex.X_add_number != 0)
        {
@@ -3538,9 +3441,7 @@ load_address (counter, reg, ep)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          ex.X_op = O_constant;
          macro_build ((char *) NULL, counter, &ex,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa  < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
@@ -3550,15 +3451,26 @@ load_address (counter, reg, ep)
           addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
         */
       macro_build ((char *) NULL, counter, ep,
-                  ((bfd_arch_bits_per_address (stdoutput) == 32
-                    || mips_opts.isa  < 3)
-                   ? "addiu" : "daddiu"),
+                  HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                   "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
     }
   else
     abort ();
 }
 
+/* Move the contents of register SOURCE into register DEST.  */
+
+static void
+move_register (counter, dest, source)
+     int *counter;
+     int dest;
+     int source;
+{
+  macro_build ((char *) NULL, counter, (expressionS *) NULL,
+              HAVE_32BIT_GPRS ? "addu" : "daddu",
+              "d,v,t", dest, source, 0);
+}
+
 /*
  *                     Build macros
  *   This routine implements the seemingly endless macro or synthesized
@@ -3585,7 +3497,7 @@ macro (ip)
   int tempreg;
   int mask;
   int icnt = 0;
-  int used_at;
+  int used_at = 0;
   expressionS expr1;
   const char *s;
   const char *s2;
@@ -3632,10 +3544,9 @@ macro (ip)
       if (dreg == sreg)
        macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
       else
-       macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, sreg, 0);
+       move_register (&icnt, dreg, sreg);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dsub" : "sub",
-                  "d,v,t", dreg, 0, sreg);
+                  dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
 
       --mips_opts.noreorder;
       return;
@@ -3750,8 +3661,7 @@ macro (ip)
        }
       macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTL_I:
@@ -3759,7 +3669,7 @@ macro (ip)
     case M_BGT_I:
       /* check for > max integer */
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3768,18 +3678,22 @@ macro (ip)
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
        {
        do_false:
          /* result is always false */
          if (! likely)
            {
-             as_warn (_("Branch %s is always false (nop)"), ip->insn_mo->name);
+             if (warn_nops)
+               as_warn (_("Branch %s is always false (nop)"),
+                        ip->insn_mo->name);
              macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
            }
          else
            {
-             as_warn (_("Branch likely %s is always false"), ip->insn_mo->name);
+             if (warn_nops)
+               as_warn (_("Branch likely %s is always false"),
+                        ip->insn_mo->name);
              macro_build ((char *) NULL, &icnt, &offset_expr, "bnel",
                           "s,t,p", 0, 0);
            }
@@ -3796,19 +3710,17 @@ macro (ip)
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgezl" : "bgez",
-                      "s,p", sreg);
+                      likely ? "bgezl" : "bgez", "s,p", sreg);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgtzl" : "bgtz",
-                      "s,p", sreg);
+                      likely ? "bgtzl" : "bgtz", "s,p", sreg);
          return;
        }
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3818,7 +3730,7 @@ macro (ip)
       maxnum = - maxnum - 1;
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number <= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
        {
        do_true:
          /* result is always true */
@@ -3828,8 +3740,7 @@ macro (ip)
        }
       set_at (&icnt, sreg, 0);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGEUL:
@@ -3840,22 +3751,20 @@ macro (ip)
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "beql" : "beq",
-                      "s,t,p", 0, treg);
+                      likely ? "beql" : "beq", "s,t,p", 0, treg);
          return;
        }
       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg,
                   treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTUL_I:
       likely = 1;
     case M_BGTU_I:
       if (sreg == 0
-         || (mips_opts.isa < 3
+         || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == 0xffffffff))
        goto do_false;
@@ -3872,14 +3781,12 @@ macro (ip)
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bnel" : "bne",
-                      "s,t,p", sreg, 0);
+                      likely ? "bnel" : "bne", "s,t,p", sreg, 0);
          return;
        }
       set_at (&icnt, sreg, 1);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BGTL:
@@ -3888,21 +3795,18 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgtzl" : "bgtz",
-                      "s,p", sreg);
+                      likely ? "bgtzl" : "bgtz", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bltzl" : "bltz",
-                      "s,p", treg);
+                      likely ? "bltzl" : "bltz", "s,p", treg);
          return;
        }
       macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BGTUL:
@@ -3911,8 +3815,7 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bnel" : "bne",
-                      "s,t,p", sreg, 0);
+                      likely ? "bnel" : "bne", "s,t,p", sreg, 0);
          return;
        }
       if (sreg == 0)
@@ -3920,8 +3823,7 @@ macro (ip)
       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg,
                   sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLEL:
@@ -3930,28 +3832,25 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "blezl" : "blez",
-                      "s,p", sreg);
+                      likely ? "blezl" : "blez", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgezl" : "bgez",
-                      "s,p", treg);
+                      likely ? "bgezl" : "bgez", "s,p", treg);
          return;
        }
       macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, treg, sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BLEL_I:
       likely = 1;
     case M_BLE_I:
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3960,7 +3859,7 @@ macro (ip)
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -3973,21 +3872,18 @@ macro (ip)
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bltzl" : "bltz",
-                      "s,p", sreg);
+                      likely ? "bltzl" : "bltz", "s,p", sreg);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "blezl" : "blez",
-                      "s,p", sreg);
+                      likely ? "blezl" : "blez", "s,p", sreg);
          return;
        }
       set_at (&icnt, sreg, 0);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLEUL:
@@ -3996,8 +3892,7 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "beql" : "beq",
-                      "s,t,p", sreg, 0);
+                      likely ? "beql" : "beq", "s,t,p", sreg, 0);
          return;
        }
       if (sreg == 0)
@@ -4005,15 +3900,14 @@ macro (ip)
       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, treg,
                   sreg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "beql" : "beq",
-                  "s,t,p", AT, 0);
+                  likely ? "beql" : "beq", "s,t,p", AT, 0);
       break;
 
     case M_BLEUL_I:
       likely = 1;
     case M_BLEU_I:
       if (sreg == 0
-         || (mips_opts.isa < 3
+         || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == 0xffffffff))
        goto do_true;
@@ -4036,8 +3930,7 @@ macro (ip)
        }
       set_at (&icnt, sreg, 1);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLTL:
@@ -4046,21 +3939,18 @@ macro (ip)
       if (treg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bltzl" : "bltz",
-                      "s,p", sreg);
+                      likely ? "bltzl" : "bltz", "s,p", sreg);
          return;
        }
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bgtzl" : "bgtz",
-                      "s,p", treg);
+                      likely ? "bgtzl" : "bgtz", "s,p", treg);
          return;
        }
       macro_build ((char *) NULL, &icnt, NULL, "slt", "d,v,t", AT, sreg, treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_BLTUL:
@@ -4071,15 +3961,13 @@ macro (ip)
       if (sreg == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      likely ? "bnel" : "bne",
-                      "s,t,p", 0, treg);
+                      likely ? "bnel" : "bne", "s,t,p", 0, treg);
          return;
        }
       macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", AT, sreg,
                   treg);
       macro_build ((char *) NULL, &icnt, &offset_expr,
-                  likely ? "bnel" : "bne",
-                  "s,t,p", AT, 0);
+                  likely ? "bnel" : "bne", "s,t,p", AT, 0);
       break;
 
     case M_DDIV_3:
@@ -4098,12 +3986,7 @@ macro (ip)
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
          else
-           /* start-sanitize-r5900 */
-           if (mips_5900)
-             macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-           else
-           /* end-sanitize-r5900 */
-             macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
          return;
        }
 
@@ -4114,22 +3997,15 @@ macro (ip)
        {
          macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", treg, 0);
          macro_build ((char *) NULL, &icnt, NULL,
-                      dbl ? "ddiv" : "div",
-                      "z,s,t", sreg, treg);
+                      dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
       else
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
          macro_build ((char *) NULL, &icnt, NULL,
-                      dbl ? "ddiv" : "div",
-                      "z,s,t", sreg, treg);
-         /* start-sanitize-r5900 */
-         if (mips_5900)
-           macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-         else
-           /* end-sanitize-r5900 */
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+                      dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
        }
       expr1.X_add_number = -1;
       macro_build ((char *) NULL, &icnt, &expr1,
@@ -4168,12 +4044,7 @@ macro (ip)
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
 
-         /* start-sanitize-r5900 */
-         if (mips_5900)
-           macro_build ((char *) NULL, &icnt, NULL, "break", "B", 6);
-         else
-           /* end-sanitize-r5900 */
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
       break;
@@ -4220,21 +4091,15 @@ macro (ip)
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
          else
-           /* start-sanitize-r5900 */
-           if (mips_5900)
-             macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-           else
-             /* end-sanitize-r5900 */
-             macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          if (strcmp (s2, "mflo") == 0)
-           macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg,
-                        sreg);
+           move_register (&icnt, dreg, sreg);
          else
-           macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
+           move_register (&icnt, dreg, 0);
          return;
        }
       if (imm_expr.X_op == O_constant
@@ -4243,15 +4108,11 @@ macro (ip)
        {
          if (strcmp (s2, "mflo") == 0)
            {
-             if (dbl)
-               macro_build ((char *) NULL, &icnt, NULL, "dneg", "d,w", dreg,
-                            sreg);
-             else
-               macro_build ((char *) NULL, &icnt, NULL, "neg", "d,w", dreg,
-                            sreg);
+             macro_build ((char *) NULL, &icnt, NULL, dbl ? "dneg" : "neg",
+                          "d,w", dreg, sreg);
            }
          else
-           macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
+           move_register (&icnt, dreg, 0);
          return;
        }
 
@@ -4296,12 +4157,7 @@ macro (ip)
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
-         /* start-sanitize-r5900 */
-         if (mips_5900)
-           macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-         else
-           /* end-sanitize-r5900 */
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
        }
       macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
       return;
@@ -4315,29 +4171,28 @@ macro (ip)
       /* When generating embedded PIC code, we permit expressions of
         the form
           la   $4,foo-bar
-        where bar is an address in the .text section.  These are used
+        where bar is an address in the current section.  These are used
         when getting the addresses of functions.  We don't permit
         X_add_number to be non-zero, because if the symbol is
         external the relaxing code needs to know that any addend is
         purely the offset to X_op_symbol.  */
       if (mips_pic == EMBEDDED_PIC
          && offset_expr.X_op == O_subtract
-         && now_seg == text_section
-         && (offset_expr.X_op_symbol->sy_value.X_op == O_constant
-             ? S_GET_SEGMENT (offset_expr.X_op_symbol) == text_section
-             : (offset_expr.X_op_symbol->sy_value.X_op == O_symbol
-                && (S_GET_SEGMENT (offset_expr.X_op_symbol
-                                   ->sy_value.X_add_symbol)
-                    == text_section)))
+         && (symbol_constant_p (offset_expr.X_op_symbol)
+             ? S_GET_SEGMENT (offset_expr.X_op_symbol) == now_seg
+             : (symbol_equated_p (offset_expr.X_op_symbol)
+                && (S_GET_SEGMENT
+                    (symbol_get_value_expression (offset_expr.X_op_symbol)
+                     ->X_add_symbol)
+                    == now_seg)))
          && breg == 0
-         && offset_expr.X_add_number == 0)
+         && (offset_expr.X_add_number == 0
+             || OUTPUT_FLAVOR == bfd_target_elf_flavour))
        {
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       treg, (int) BFD_RELOC_PCREL_HI16_S);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa  < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", treg, treg, (int) BFD_RELOC_PCREL_LO16);
          return;
        }
@@ -4371,16 +4226,14 @@ macro (ip)
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
             If we have a constant, we need two instructions anyhow,
             so we may as well always use the latter form.  */
-         if ((valueT) offset_expr.X_add_number >= MAX_GPREL_OFFSET
+         if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
              || nopic_need_relax (offset_expr.X_add_symbol, 1))
            p = NULL;
          else
            {
              frag_grow (20);
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa  < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
              p = frag_var (rs_machine_dependent, 8, 0,
                            RELAX_ENCODE (4, 8, 0, 4, 0,
@@ -4392,16 +4245,18 @@ macro (ip)
          if (p != NULL)
            p += 4;
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa  < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
+         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
          /* If this is a reference to an external symbol, and there
             is no constant, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
+            or if tempreg is PIC_CALL_REG
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_CALL16)
             For a local symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
@@ -4428,9 +4283,11 @@ macro (ip)
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          frag_grow (32);
+         if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+           lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       dbl ? "ld" : "lw",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      "t,o(b)", tempreg, lw_reloc_type, GP);
          if (expr1.X_add_number == 0)
            {
              int off;
@@ -4459,9 +4316,7 @@ macro (ip)
                  p += 4;
                }
              macro_build (p, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              /* FIXME: If breg == 0, and the next instruction uses
                 $tempreg, then if this variant case is used an extra
@@ -4473,9 +4328,7 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           "nop", "");
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              (void) frag_var (rs_machine_dependent, 0, 0,
                               RELAX_ENCODE (0, 0, -12, -4, 0, 0),
@@ -4500,9 +4353,7 @@ macro (ip)
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               "nop", "");
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              ((bfd_arch_bits_per_address (stdoutput) == 32
-                                || mips_opts.isa < 3)
-                               ? "addu" : "daddu"),
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", treg, AT, breg);
                  breg = 0;
                  tempreg = treg;
@@ -4517,14 +4368,10 @@ macro (ip)
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, tempreg, AT);
              (void) frag_var (rs_machine_dependent, 0, 0,
                               RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
@@ -4536,12 +4383,18 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          int gpdel;
+         int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
 
          /* This is the large GOT case.  If this is a reference to an
             external symbol, and there is no constant, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
               addu     $tempreg,$tempreg,$gp
               lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+            or if tempreg is PIC_CALL_REG
+              lui      $tempreg,<sym>          (BFD_RELOC_MIPS_CALL_HI16)
+              addu     $tempreg,$tempreg,$gp
+              lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
             For a local symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
@@ -4580,17 +4433,19 @@ macro (ip)
            gpdel = 4;
          else
            gpdel = 0;
+         if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+           {
+             lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+             lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+           }
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
-                      tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+                      tempreg, lui_reloc_type);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addu" : "daddu"),
+                      HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                       "d,v,t", tempreg, tempreg, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       dbl ? "ld" : "lw",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
-                      tempreg);
+                      "t,o(b)", tempreg, lw_reloc_type, tempreg);
          if (expr1.X_add_number == 0)
            {
              int off;
@@ -4622,9 +4477,7 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           "nop", "");
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
 
              p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
@@ -4657,9 +4510,7 @@ macro (ip)
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               "nop", "");
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              ((bfd_arch_bits_per_address (stdoutput) == 32
-                                || mips_opts.isa < 3)
-                               ? "addu" : "daddu"),
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", treg, AT, breg);
                  dreg = treg;
                  adj = 8;
@@ -4673,14 +4524,10 @@ macro (ip)
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", dreg, dreg, AT);
 
              p = frag_var (rs_machine_dependent, 16 + gpdel + adj, 0,
@@ -4712,9 +4559,7 @@ macro (ip)
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
              p += 4;
              macro_build (p, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              /* FIXME: If add_number is 0, and there was no base
                  register, the external symbol case ended with a load,
@@ -4732,9 +4577,7 @@ macro (ip)
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
                  p += 4;
                  macro_build (p, &icnt, (expressionS *) NULL,
-                              ((bfd_arch_bits_per_address (stdoutput) == 32
-                                || mips_opts.isa < 3)
-                               ? "addu" : "daddu"),
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", treg, AT, breg);
                  p += 4;
                  tempreg = treg;
@@ -4746,15 +4589,11 @@ macro (ip)
              macro_build_lui (p, &icnt, &expr1, AT);
              p += 4;
              macro_build (p, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addiu" : "daddiu"),
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              p += 4;
              macro_build (p, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, tempreg, AT);
              p += 4;
            }
@@ -4765,9 +4604,7 @@ macro (ip)
               addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
             */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
        }
       else
@@ -4775,9 +4612,7 @@ macro (ip)
 
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    ((bfd_arch_bits_per_address (stdoutput) == 32
-                      || mips_opts.isa < 3)
-                     ? "addu" : "daddu"),
+                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                     "d,v,t", treg, tempreg, breg);
 
       if (! used_at)
@@ -4810,7 +4645,7 @@ macro (ip)
        {
          if (sreg != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
-      
+
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
                       "d,s", dreg, sreg);
          if (mips_cprestore_offset < 0)
@@ -4819,9 +4654,7 @@ macro (ip)
            {
              expr1.X_add_number = mips_cprestore_offset;
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "lw" : "ld"),
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
            }
        }
@@ -4862,9 +4695,7 @@ macro (ip)
          if (! mips_big_got)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "lw" : "ld"),
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_CALL16, GP);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -4885,14 +4716,10 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                           PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL_HI16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", PIC_CALL_REG, PIC_CALL_REG, GP);
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "lw" : "ld"),
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -4908,19 +4735,15 @@ macro (ip)
                  p += 4;
                }
              macro_build (p, &icnt, &offset_expr,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "lw" : "ld"),
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_GOT16, GP);
              p += 4;
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
              p += 4;
-           }                      
+           }
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
                       (int) BFD_RELOC_LO16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -4934,9 +4757,7 @@ macro (ip)
                             "nop", "");
              expr1.X_add_number = mips_cprestore_offset;
              macro_build ((char *) NULL, &icnt, &expr1,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "lw" : "ld"),
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", GP, (int) BFD_RELOC_LO16,
                           mips_frame_reg);
            }
@@ -4970,22 +4791,22 @@ macro (ip)
       goto ld;
     case M_LWC0_AB:
       s = "lwc0";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LWC1_AB:
       s = "lwc1";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LWC2_AB:
       s = "lwc2";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LWC3_AB:
       s = "lwc3";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LWL_AB:
@@ -4997,23 +4818,23 @@ macro (ip)
       lr = 1;
       goto ld;
     case M_LDC1_AB:
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
        }
       s = "ldc1";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LDC2_AB:
       s = "ldc2";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LDC3_AB:
       s = "ldc3";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld;
     case M_LDL_AB:
@@ -5055,22 +4876,22 @@ macro (ip)
       goto st;
     case M_SWC0_AB:
       s = "swc0";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SWC1_AB:
       s = "swc1";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SWC2_AB:
       s = "swc2";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SWC3_AB:
       s = "swc3";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SWL_AB:
@@ -5086,23 +4907,23 @@ macro (ip)
       s = "scd";
       goto st;
     case M_SDC1_AB:
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
        }
       s = "sdc1";
       coproc = 1;
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       goto st;
     case M_SDC2_AB:
       s = "sdc2";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SDC3_AB:
       s = "sdc3";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto st;
     case M_SDL_AB:
@@ -5114,7 +4935,7 @@ macro (ip)
       tempreg = AT;
       used_at = 1;
     ld_st:
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       if (mask == M_LWC1_AB
          || mask == M_SWC1_AB
          || mask == M_LDC1_AB
@@ -5159,7 +4980,7 @@ macro (ip)
             With a constant we always use the latter case.  */
          if (breg == 0)
            {
-             if ((valueT) offset_expr.X_add_number >= MAX_GPREL_OFFSET
+             if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
                  || nopic_need_relax (offset_expr.X_add_symbol, 1))
                p = NULL;
              else
@@ -5184,16 +5005,14 @@ macro (ip)
            }
          else
            {
-             if ((valueT) offset_expr.X_add_number >= MAX_GPREL_OFFSET
+             if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
                  || nopic_need_relax (offset_expr.X_add_symbol, 1))
                p = NULL;
              else
                {
                  frag_grow (28);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              ((bfd_arch_bits_per_address (stdoutput) == 32
-                                || mips_opts.isa < 3)
-                               ? "addu" : "daddu"),
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", tempreg, breg, GP);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                               treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5206,9 +5025,7 @@ macro (ip)
              if (p != NULL)
                p += 4;
              macro_build (p, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, tempreg, breg);
              if (p != NULL)
                p += 4;
@@ -5241,25 +5058,19 @@ macro (ip)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          frag_grow (20);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
-         p = frag_var (rs_machine_dependent, 4, 0, 
+         p = frag_var (rs_machine_dependent, 4, 0,
                        RELAX_ENCODE (0, 4, -8, 0, 0, 0),
                        offset_expr.X_add_symbol, (offsetT) 0,
                        (char *) NULL);
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        ((bfd_arch_bits_per_address (stdoutput) == 32
-                          || mips_opts.isa < 3)
-                         ? "addu" : "daddu"),
+                        HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                         "d,v,t", tempreg, tempreg, breg);
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
                       (int) BFD_RELOC_LO16, tempreg);
@@ -5298,14 +5109,10 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addu" : "daddu"),
+                      HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                       "d,v,t", tempreg, tempreg, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
                       tempreg);
          p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
@@ -5317,23 +5124,17 @@ macro (ip)
              p += 4;
            }
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
          p += 4;
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        ((bfd_arch_bits_per_address (stdoutput) == 32
-                          || mips_opts.isa < 3)
-                         ? "addu" : "daddu"),
+                        HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                         "d,v,t", tempreg, tempreg, breg);
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
                       (int) BFD_RELOC_LO16, tempreg);
@@ -5356,9 +5157,7 @@ macro (ip)
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", tempreg, breg, GP);
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5402,13 +5201,13 @@ macro (ip)
        }
 
     case M_LI_D:
-      /* If we have a constant in IMM_EXPR, then in mips3 mode it is
-         the entire value, and in mips1 mode it is the high order 32
-         bits of the value and the low order 32 bits are either zero
-         or in offset_expr.  */
+      /* Check if we have a constant in IMM_EXPR.  If the GPRs are 64 bits
+         wide, IMM_EXPR is the entire value.  Otherwise IMM_EXPR is the high
+         order 32 bits of the value and the low order 32 bits are either
+         zero or in OFFSET_EXPR.  */
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
-         if (mips_opts.isa >= 3)
+         if (HAVE_64BIT_GPRS)
            load_register (&icnt, treg, &imm_expr, 1);
          else
            {
@@ -5430,8 +5229,7 @@ macro (ip)
              if (lreg <= 31)
                {
                  if (offset_expr.X_op == O_absent)
-                   macro_build ((char *) NULL, &icnt, NULL, "move", "d,s",
-                                lreg, 0);
+                   move_register (&icnt, lreg, 0);
                  else
                    {
                      assert (offset_expr.X_op == O_constant);
@@ -5452,9 +5250,7 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
        }
       else if (mips_pic == EMBEDDED_PIC)
@@ -5462,18 +5258,16 @@ macro (ip)
          /* For embedded PIC we pick up the entire address off $gp in
             a single instruction.  */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
                       "t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
          offset_expr.X_op = O_constant;
          offset_expr.X_add_number = 0;
        }
       else
        abort ();
-       
+
       /* Now we load the register(s).  */
-      if (mips_opts.isa >= 3)
+      if (HAVE_64BIT_GPRS)
        macro_build ((char *) NULL, &icnt, &offset_expr, "ld", "t,o(b)",
                     treg, (int) BFD_RELOC_LO16, AT);
       else
@@ -5498,16 +5292,20 @@ macro (ip)
       break;
 
     case M_LI_DD:
-      /* If we have a constant in IMM_EXPR, then in mips3 mode it is
-         the entire value, and in mips1 mode it is the high order 32
-         bits of the value and the low order 32 bits are either zero
-         or in offset_expr.  */
+      /* Check if we have a constant in IMM_EXPR.  If the FPRs are 64 bits
+         wide, IMM_EXPR is the entire value and the GPRs are known to be 64
+         bits wide as well.  Otherwise IMM_EXPR is the high order 32 bits of
+         the value and the low order 32 bits are either zero or in
+         OFFSET_EXPR.  */
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
-         load_register (&icnt, AT, &imm_expr, mips_opts.isa >= 3);
-         if (mips_opts.isa >= 3)
-           macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        "dmtc1", "t,S", AT, treg);
+         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_FPRS);
+         if (HAVE_64BIT_FPRS)
+           {
+             assert (HAVE_64BIT_GPRS);
+             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                          "dmtc1", "t,S", AT, treg);
+           }
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -5531,7 +5329,7 @@ macro (ip)
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
-         if (mips_opts.isa >= 2)
+         if (mips_opts.isa != ISA_MIPS1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
@@ -5546,17 +5344,15 @@ macro (ip)
          assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          if (mips_pic == SVR4_PIC)
            macro_build ((char *) NULL, &icnt, &offset_expr,
-                        ((bfd_arch_bits_per_address (stdoutput) == 32
-                          || mips_opts.isa < 3)
-                         ? "lw" : "ld"),
+                        HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                         "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          else
            {
              /* FIXME: This won't work for a 64 bit address.  */
              macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
            }
-             
-         if (mips_opts.isa >= 2)
+
+         if (mips_opts.isa != ISA_MIPS1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_LO16, AT);
@@ -5574,7 +5370,7 @@ macro (ip)
        }
 
     case M_L_DOB:
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
@@ -5583,7 +5379,7 @@ macro (ip)
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa < 2);
+      assert (mips_opts.isa == ISA_MIPS1);
       macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg,
                   (int) r, breg);
@@ -5615,14 +5411,14 @@ macro (ip)
        * But, the resulting address is the same after relocation so why
        * generate the extra instruction?
        */
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
        }
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
-      if (mips_opts.isa >= 2)
+      if (mips_opts.isa != ISA_MIPS1)
        {
          s = "ldc1";
          goto ld;
@@ -5633,13 +5429,13 @@ macro (ip)
       goto ldd_std;
 
     case M_S_DAB:
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
        }
 
-      if (mips_opts.isa >= 2)
+      if (mips_opts.isa != ISA_MIPS1)
        {
          s = "sdc1";
          goto st;
@@ -5647,12 +5443,12 @@ macro (ip)
 
       s = "swc1";
       fmt = "T,o(b)";
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ldd_std;
 
     case M_LD_AB:
-      if (mips_opts.isa >= 3)
+      if (HAVE_64BIT_GPRS)
        {
          s = "ld";
          goto ld;
@@ -5663,7 +5459,7 @@ macro (ip)
       goto ldd_std;
 
     case M_SD_AB:
-      if (mips_opts.isa >= 3)
+      if (HAVE_64BIT_GPRS)
        {
          s = "sd";
          goto st;
@@ -5683,7 +5479,7 @@ macro (ip)
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  We set coproc if we must
         load $fn+1 first.  */
-      /* Itbl support may require additional care here. */
+      /* Itbl support may require additional care here.  */
       if (! target_big_endian)
        coproc = 0;
 
@@ -5704,7 +5500,7 @@ macro (ip)
             If there is a base register, we add it to $at after the
             lui instruction.  If there is a constant, we always use
             the last case.  */
-         if ((valueT) offset_expr.X_add_number >= MAX_GPREL_OFFSET
+         if ((valueT) offset_expr.X_add_number > MAX_GPREL_OFFSET
              || nopic_need_relax (offset_expr.X_add_symbol, 1))
            {
              p = NULL;
@@ -5725,16 +5521,14 @@ macro (ip)
                {
                  frag_grow (36);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              ((bfd_arch_bits_per_address (stdoutput) == 32
-                                || mips_opts.isa < 3)
-                               ? "addu" : "daddu"),
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                               "d,v,t", AT, breg, GP);
                  tempreg = AT;
                  off = 4;
                  used_at = 1;
                }
 
-              /* Itbl support may require additional care here. */
+             /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg + 1 : treg,
                           (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5744,7 +5538,7 @@ macro (ip)
                  undesired nop.  */
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
-              /* Itbl support may require additional care here. */
+             /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg : treg + 1,
                           (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5783,14 +5577,12 @@ macro (ip)
          if (breg != 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", AT, breg, AT);
              if (p != NULL)
                p += 4;
            }
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5798,11 +5590,11 @@ macro (ip)
            p += 4;
          /* FIXME: How do we handle overflow here?  */
          offset_expr.X_add_number += 4;
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
-       }         
+       }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
          int off;
@@ -5832,18 +5624,14 @@ macro (ip)
            off = 4;
          frag_grow (24 + off);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        ((bfd_arch_bits_per_address (stdoutput) == 32
-                          || mips_opts.isa < 3)
-                         ? "addu" : "daddu"),
+                        HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                         "d,v,t", AT, breg, AT);
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5853,7 +5641,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5901,23 +5689,17 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       AT, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addu" : "daddu"),
+                      HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                       "d,v,t", AT, AT, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT_LO16, AT);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        ((bfd_arch_bits_per_address (stdoutput) == 32
-                          || mips_opts.isa < 3)
-                         ? "addu" : "daddu"),
+                        HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                         "d,v,t", AT, breg, AT);
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5927,7 +5709,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5945,9 +5727,7 @@ macro (ip)
              p += 4;
            }
          macro_build (p, &icnt, &offset_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "lw" : "ld"),
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -5955,13 +5735,11 @@ macro (ip)
          if (breg != 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", AT, breg, AT);
              p += 4;
            }
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5972,7 +5750,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5996,20 +5774,18 @@ macro (ip)
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          ((bfd_arch_bits_per_address (stdoutput) == 32
-                            || mips_opts.isa < 3)
-                           ? "addu" : "daddu"),
+                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                           "d,v,t", AT, breg, GP);
              tempreg = AT;
              used_at = 1;
            }
 
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_MIPS_GPREL, tempreg);
          offset_expr.X_add_number += 4;
-          /* Itbl support may require additional care here. */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -6028,7 +5804,7 @@ macro (ip)
     case M_SD_OB:
       s = "sw";
     sd_ob:
-      assert (bfd_arch_bits_per_address (stdoutput) == 32 || mips_opts.isa < 3);
+      assert (HAVE_32BIT_ADDRESSES);
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
@@ -6048,10 +5824,10 @@ macro (ip)
       What are the side-effects of the cop instruction?
       What cache support might we have and what are its effects?
       Both coprocessor & memory require delays. how long???
-      What registers are read/set/modified? 
+      What registers are read/set/modified?
 
       If an itbl is provided to interpret cop instructions,
-      this knowledge can be encoded in the itbl spec. */
+      this knowledge can be encoded in the itbl spec.  */
 
     case M_COP0:
       s = "c0";
@@ -6071,32 +5847,36 @@ macro (ip)
                   ip->insn_opcode);
       return;
 
+    case M_MOVE:
+      move_register (&icnt, dreg, sreg);
+      return;
+
 #ifdef LOSING_COMPILER
     default:
       /* Try and see if this is a new itbl instruction.
          This code builds table entries out of the macros in mip_opcodes.
          FIXME: For now we just assemble the expression and pass it's
          value along as a 32-bit immediate.
-         We may want to have the assembler assemble this value, 
+         We may want to have the assembler assemble this value,
          so that we gain the assembler's knowledge of delay slots,
          symbols, etc.
          Would it be more efficient to use mask (id) here? */
-      if (itbl_have_entries 
+      if (itbl_have_entries
          && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
-        {
+       {
          s = ip->insn_mo->name;
          s2 = "cop3";
          coproc = ITBL_DECODE_PNUM (immed_expr);;
          macro_build ((char *) NULL, &icnt, &immed_expr, s, "C");
          return;
-        }
+       }
       macro2 (ip);
       return;
     }
   if (mips_opts.noat)
     as_warn (_("Macro used $at after \".set noat\""));
 }
-          
+
 static void
 macro2 (ip)
      struct mips_cl_insn *ip;
@@ -6119,17 +5899,17 @@ macro2 (ip)
   offsetT maxnum;
   bfd_reloc_code_real_type r;
   char *p;
-          
+
   treg = (ip->insn_opcode >> 16) & 0x1f;
   dreg = (ip->insn_opcode >> 11) & 0x1f;
   sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
   mask = ip->insn_mo->mask;
-          
+
   expr1.X_op = O_constant;
   expr1.X_op_symbol = NULL;
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
-          
+
   switch (mask)
     {
 #endif /* LOSING_COMPILER */
@@ -6151,8 +5931,7 @@ macro2 (ip)
         anyway.  */
       load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dmult" : "mult",
-                  "s,t", sreg, AT);
+                  dbl ? "dmult" : "mult", "s,t", sreg, AT);
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       break;
 
@@ -6172,12 +5951,10 @@ macro2 (ip)
       if (imm)
        load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dmult" : "mult",
-                  "s,t", sreg, imm ? AT : treg);
+                  dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dsra32" : "sra",
-                  "d,w,<", dreg, dreg, 31);
+                  dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, 31);
       macro_build ((char *) NULL, &icnt, NULL, "mfhi", "d", AT);
       if (mips_trap)
        macro_build ((char *) NULL, &icnt, NULL, "tne", "s,t", dreg, AT);
@@ -6186,12 +5963,7 @@ macro2 (ip)
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", dreg, AT);
          macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         /* start-sanitize-r5900 */
-         if (mips_5900)
-           macro_build ((char *) NULL, &icnt, NULL, "break", "B", 6);
-         else
-           /* end-sanitize-r5900 */
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
@@ -6224,12 +5996,7 @@ macro2 (ip)
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", AT, 0);
          macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         /* start-sanitize-r5900 */
-         if (mips_5900)
-           macro_build ((char *) NULL, &icnt, NULL, "break", "B", 6);
-         else
-           /* end-sanitize-r5900 */
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
       break;
@@ -6271,12 +6038,12 @@ macro2 (ip)
       break;
 
     case M_S_DOB:
-      if (mips_4650)
+      if (mips_arch == CPU_R4650)
        {
          as_bad (_("opcode not supported on this processor"));
          return;
        }
-      assert (mips_opts.isa < 2);
+      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 ((char *) NULL, &icnt, &offset_expr, "swc1", "T,o(b)",
@@ -6315,7 +6082,7 @@ macro2 (ip)
        {
          as_warn (_("Instruction %s: result is always false"),
                   ip->insn_mo->name);
-         macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
+         move_register (&icnt, dreg, 0);
          return;
        }
       if (imm_expr.X_op == O_constant
@@ -6332,9 +6099,7 @@ macro2 (ip)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg,
                       (int) BFD_RELOC_LO16);
          used_at = 0;
@@ -6485,9 +6250,7 @@ macro2 (ip)
          as_warn (_("Instruction %s: result is always true"),
                   ip->insn_mo->name);
          macro_build ((char *) NULL, &icnt, &expr1,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, 0, (int) BFD_RELOC_LO16);
          return;
        }
@@ -6505,9 +6268,7 @@ macro2 (ip)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
-                      ((bfd_arch_bits_per_address (stdoutput) == 32
-                        || mips_opts.isa < 3)
-                       ? "addiu" : "daddiu"),
+                      HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, (int) BFD_RELOC_LO16);
          used_at = 0;
        }
@@ -6538,8 +6299,7 @@ macro2 (ip)
        }
       load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dsub" : "sub",
-                  "d,v,t", dreg, sreg, AT);
+                  dbl ? "dsub" : "sub", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_DSUBU_I:
@@ -6557,8 +6317,7 @@ macro2 (ip)
        }
       load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dsubu" : "subu",
-                  "d,v,t", dreg, sreg, AT);
+                  dbl ? "dsubu" : "subu", "d,v,t", dreg, sreg, AT);
       break;
 
     case M_TEQ_I:
@@ -6583,9 +6342,9 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, NULL, s, "s,t", sreg, AT);
       break;
 
-    case M_TRUNCWD:
     case M_TRUNCWS:
-      assert (mips_opts.isa < 2);
+    case M_TRUNCWD:
+      assert (mips_opts.isa == ISA_MIPS1);
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
 
@@ -6674,9 +6433,7 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    ((bfd_arch_bits_per_address (stdoutput) == 32
-                      || mips_opts.isa < 3)
-                     ? "addu" : "daddu"),
+                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
@@ -6697,9 +6454,7 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    ((bfd_arch_bits_per_address (stdoutput) == 32
-                      || mips_opts.isa < 3)
-                     ? "addu" : "daddu"),
+                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                     "d,v,t", AT, AT, breg);
       if (target_big_endian)
        expr1.X_add_number = 0;
@@ -6771,9 +6526,7 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    ((bfd_arch_bits_per_address (stdoutput) == 32
-                      || mips_opts.isa < 3)
-                     ? "addu" : "daddu"),
+                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
@@ -6793,9 +6546,7 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    ((bfd_arch_bits_per_address (stdoutput) == 32
-                      || mips_opts.isa < 3)
-                     ? "addu" : "daddu"),
+                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = 0;
@@ -6823,7 +6574,7 @@ macro2 (ip)
 
     default:
       /* FIXME: Check if this is one of the itbl macros, since they
-        are added dynamically. */
+        are added dynamically.  */
       as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
       break;
     }
@@ -6882,13 +6633,8 @@ mips16_macro (ip)
                   "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      /* start-sanitize-r5900 */
-      if (mips_5900)
-       macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-      else
-       /* end-sanitize-r5900 */
-       macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
-      
+      macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+
       /* FIXME: The normal code checks for of -1 / -0x80000000 here,
          since that causes an overflow.  We should do that as well,
          but I don't see how to do the comparisons without a temporary
@@ -6919,11 +6665,6 @@ mips16_macro (ip)
       macro_build ((char *) NULL, &icnt, NULL, s, "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      /* start-sanitize-r5900 */
-      if (mips_5900)
-       macro_build ((char *) NULL, &icnt, NULL, "break", "B", 7);
-      else
-       /* end-sanitize-r5900 */
        macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
       --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, s2, "x", zreg);
@@ -6933,8 +6674,7 @@ mips16_macro (ip)
       dbl = 1;
     case M_MUL:
       macro_build ((char *) NULL, &icnt, NULL,
-                  dbl ? "dmultu" : "multu",
-                  "x,y", xreg, yreg);
+                  dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "x", zreg);
       return;
 
@@ -6947,8 +6687,7 @@ mips16_macro (ip)
        as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr,
-                  dbl ? "daddiu" : "addiu",
-                  "y,x,4", yreg, xreg);
+                  dbl ? "daddiu" : "addiu", "y,x,4", yreg, xreg);
       break;
 
     case M_SUBU_I_2:
@@ -7082,8 +6821,7 @@ mips16_macro (ip)
       expr1.X_add_number = 0;
       macro_build ((char *) NULL, &icnt, &expr1, "slti", "x,8",  yreg);
       if (xreg != yreg)
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    "move", "y,X", xreg, yreg);
+       move_register (&icnt, xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bteqz", "p");
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -7118,13 +6856,15 @@ validate_mips_insn (opc)
       case '<': USE_BITS (OP_MASK_SHAMT,       OP_SH_SHAMT);   break;
       case '>':        USE_BITS (OP_MASK_SHAMT,        OP_SH_SHAMT);   break;
       case 'A': break;
-      case 'B':        USE_BITS (OP_MASK_SYSCALL,      OP_SH_SYSCALL); break;
+      case 'B': USE_BITS (OP_MASK_CODE20,       OP_SH_CODE20);  break;
       case 'C':        USE_BITS (OP_MASK_COPZ,         OP_SH_COPZ);    break;
       case 'D':        USE_BITS (OP_MASK_FD,           OP_SH_FD);      break;
       case 'E':        USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
       case 'F': break;
       case 'G':        USE_BITS (OP_MASK_RD,           OP_SH_RD);      break;
+      case 'H': USE_BITS (OP_MASK_SEL,         OP_SH_SEL);     break;
       case 'I': break;
+      case 'J': USE_BITS (OP_MASK_CODE19,       OP_SH_CODE19);  break;
       case 'L': break;
       case 'M':        USE_BITS (OP_MASK_CCC,          OP_SH_CCC);     break;
       case 'N':        USE_BITS (OP_MASK_BCC,          OP_SH_BCC);     break;
@@ -7155,43 +6895,8 @@ validate_mips_insn (opc)
       case 'x': break;
       case 'z': break;
       case 'P': USE_BITS (OP_MASK_PERFREG,     OP_SH_PERFREG); break;
-       /* start-sanitize-r5900 */
-      case '0': USE_BITS (OP_MASK_VADDI,       OP_SH_VADDI);   break;
-      case '1': USE_BITS (OP_MASK_VUTREG,      OP_SH_VUTREG);  break;
-      case '2': USE_BITS (OP_MASK_VUSREG,      OP_SH_VUSREG);  break;
-      case '3': USE_BITS (OP_MASK_VUDREG,      OP_SH_VUDREG);  break;
-      case '4': USE_BITS (OP_MASK_VUTREG,      OP_SH_VUTREG);  break;
-      case '5': USE_BITS (OP_MASK_VUSREG,      OP_SH_VUSREG);  break;
-      case '6': USE_BITS (OP_MASK_VUDREG,      OP_SH_VUDREG);  break;
-      case '7':
-       USE_BITS (OP_MASK_VUTREG,               OP_SH_VUTREG);
-       USE_BITS (OP_MASK_VUFTF,                OP_SH_VUFTF);
-       break;
-      case '8':
-       USE_BITS (OP_MASK_VUSREG,               OP_SH_VUSREG);
-       USE_BITS (OP_MASK_VUFSF,                OP_SH_VUFSF);
-       break;
-      case '9': break;
-      case 'K': break;
-      case 'X': break;
-      case 'U': break;
-      case 'Q': break;
-      case 'J': break;
-      case 'O': USE_BITS (OP_MASK_VUCALLMS,    OP_SH_VUCALLMS);break;
-      case '&': USE_BITS (OP_MASK_VUDEST,      OP_SH_VUDEST);  break;
-      case ';': break;
-      case '#':
-       p++;
-        break;
-      case '-': break;
-      case '+': break;
-       /* end-sanitize-r5900 */
-       /* start-sanitize-cygnus */
-      case 'e': USE_BITS (OP_MASK_VECBYTE,     OP_SH_VECBYTE); break;
-      case '%': USE_BITS (OP_MASK_VECALIGN,    OP_SH_VECALIGN); break;
-      case '[': break;
-      case ']': break;
-       /* end-sanitize-cygnus */
+      case 'U': USE_BITS (OP_MASK_RD,           OP_SH_RD);
+               USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
       default:
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
@@ -7219,7 +6924,7 @@ mips_ip (str, ip)
 {
   char *s;
   const char *args;
-  char c;
+  char c = 0;
   struct mips_opcode *insn;
   char *argsStart;
   unsigned int regno;
@@ -7233,18 +6938,18 @@ mips_ip (str, ip)
   /* If the instruction contains a '.', we first try to match an instruction
      including the '.'.  Then we try again without the '.'.  */
   insn = NULL;
-  for (s = str; *s != '\0' && !isspace(*s); ++s)
+  for (s = str; *s != '\0' && !isspace ((unsigned char) *s); ++s)
     continue;
 
   /* If we stopped on whitespace, then replace the whitespace with null for
      the call to hash_find.  Save the character we replaced just in case we
      have to re-parse the instruction.  */
-  if (isspace (*s))
+  if (isspace ((unsigned char) *s))
     {
       save_c = *s;
       *s++ = '\0';
     }
-       
+
   insn = (struct mips_opcode *) hash_find (op_hash, str);
 
   /* If we didn't find the instruction in the opcode table, try again, but
@@ -7252,12 +6957,12 @@ mips_ip (str, ip)
      first '.'.  */
   if (insn == NULL)
     {
-      /* Restore the character we overwrite above (if any).  */ 
+      /* Restore the character we overwrite above (if any).  */
       if (save_c)
        *(--s) = save_c;
 
       /* Scan up to the first '.' or whitespace.  */
-      for (s = str; *s != '\0' && *s != '.' && !isspace (*s); ++s)
+      for (s = str; *s != '\0' && *s != '.' && !isspace ((unsigned char) *s); ++s)
        continue;
 
       /* If we did not find a '.', then we can quit now.  */
@@ -7281,57 +6986,19 @@ mips_ip (str, ip)
   argsStart = s;
   for (;;)
     {
-      int insn_isa;
       boolean ok;
 
       assert (strcmp (insn->name, str) == 0);
 
-      if ((insn->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-      else
-       insn_isa = 15;
-
-      if (insn_isa <= mips_opts.isa)
-       ok = true;
-      else if (insn->pinfo == INSN_MACRO)
-       ok = false;
-      else if ((mips_4650 && (insn->membership & INSN_4650) != 0)
-              || (mips_4010 && (insn->membership & INSN_4010) != 0)
-              || (mips_4100 && (insn->membership & INSN_4100) != 0)
-              /* start-sanitize-vr4xxx */
-              || (mips_4121 && (insn->membership & INSN_4121) != 0)
-              /* end-sanitize-vr4xxx */
-              /* start-sanitize-vr4320 */
-              || (mips_4320 && (insn->membership & INSN_4320) != 0)
-              /* end-sanitize-vr4320 */
-              /* start-sanitize-tx49 */
-              || (mips_4900 && (insn->membership & INSN_4900) != 0)
-              /* end-sanitize-tx49 */
-              /* start-sanitize-r5900 */
-              || (mips_5900 && (insn->membership & INSN_5900) != 0)
-              /* end-sanitize-r5900 */
-              /* start-sanitize-cygnus */
-              || (mips_5400 && (insn->membership & INSN_5400) != 0)
-              /* end-sanitize-cygnus */
-              || (mips_3900 && (insn->membership & INSN_3900) != 0))
+      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_arch))
        ok = true;
       else
        ok = false;
 
       if (insn->pinfo != INSN_MACRO)
        {
-         if (mips_4650 && (insn->pinfo & FP_D) != 0)
+         if (mips_arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
            ok = false;
-         /* start-sanitize-r5900 */
-         if (mips_5900 && (insn->pinfo & FP_D) != 0)
-           ok = false;
-         /* end-sanitize-r5900 */
        }
 
       if (! ok)
@@ -7342,21 +7009,27 @@ mips_ip (str, ip)
              ++insn;
              continue;
            }
-         if (insn_isa == 15 
-              || insn_isa <= mips_opts.isa)
-           insn_error = _("opcode not supported on this processor");
          else
            {
-             static char buf[100];
+             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));
 
-             sprintf (buf, _("opcode requires -mips%d or greater"), insn_isa);
-             insn_error = buf;
+                 insn_error = buf;
+               }
+             if (save_c)
+               *(--s) = save_c;
+             return;
            }
-         return;
        }
 
       ip->insn_mo = insn;
       ip->insn_opcode = insn->match;
+      insn_error = NULL;
       for (args = insn->args;; ++args)
        {
          if (*s == ' ')
@@ -7376,16 +7049,19 @@ mips_ip (str, ip)
                {
                case 'r':
                case 'v':
-                 ip->insn_opcode |= lastregno << 21;
+                 ip->insn_opcode |= lastregno << OP_SH_RS;
                  continue;
 
                case 'w':
+                 ip->insn_opcode |= lastregno << OP_SH_RT;
+                 continue;
+
                case 'W':
-                 ip->insn_opcode |= lastregno << 16;
+                 ip->insn_opcode |= lastregno << OP_SH_FT;
                  continue;
 
                case 'V':
-                 ip->insn_opcode |= lastregno << 11;
+                 ip->insn_opcode |= lastregno << OP_SH_FS;
                  continue;
                }
              break;
@@ -7393,7 +7069,7 @@ mips_ip (str, ip)
            case '(':
              /* Handle optional base register.
                 Either the base register is omitted or
-                we must have a left paren. */
+                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'
@@ -7402,14 +7078,6 @@ mips_ip (str, ip)
                return;
 
            case ')':           /* these must match exactly */
-             /* start-sanitize-cygnus */
-           case '[':
-           case ']':
-             /* end-sanitize-cygnus */
-             /* start-sanitize-r5900 */
-           case '-':
-           case '+':
-             /* end-sanitize-r5900 */
              if (*s++ == *args)
                continue;
              break;
@@ -7427,9 +7095,9 @@ mips_ip (str, ip)
                {
                  as_warn (_("Improper shift amount (%ld)"),
                           (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number = imm_expr.X_add_number & 0x1f;
+                 imm_expr.X_add_number &= OP_MASK_SHAMT;
                }
-             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_SHAMT;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -7440,182 +7108,16 @@ mips_ip (str, ip)
              if ((unsigned long) imm_expr.X_add_number < 32
                  || (unsigned long) imm_expr.X_add_number > 63)
                break;
-             ip->insn_opcode |= (imm_expr.X_add_number - 32) << 6;
+             ip->insn_opcode |= (imm_expr.X_add_number - 32) << OP_SH_SHAMT;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
-           /* start-sanitize-r5900 */
-           case '0':           /* 5 bit signed immediate at 6 */
+           case 'k':           /* cache code */
+           case 'h':           /* prefx code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((c == '\0' && imm_expr.X_op != O_constant)
-                 || ((imm_expr.X_add_number < -16
-                      || imm_expr.X_add_number >= 16)
-                     && imm_expr.X_op == O_constant))
-               {
-                 if (imm_expr.X_op != O_constant
-                     && imm_expr.X_op != O_big)
-                   insn_error = "absolute expression required";
-                 else
-                   as_bad (_("5 bit expression not in range -16..15"));
-               }
-             ip->insn_opcode |= (imm_expr.X_add_number) << 6;
-             imm_expr.X_op = O_absent;
-             s = expr_end;
-             continue;
-
-           case '9':           /* vi27 for vcallmsr */
-             if (strncmp (s, "$vi27", 5) == 0)
-               s += 5;
-             else if (strncmp (s, "vi27", 4) == 0)
-               s += 4;
-             else
-               as_bad (_("expected vi27"));
-             continue;
-
-           case '#':           /* escape character */
-             /* '#' specifies that we've got an optional suffix to this
-                operand that must match exactly (if it exists).  */
-             if (*s != '\0' && *s != ','
-                 && *s != ' ' && *s != '\t' && *s != '\n')
-               {
-                 if (*s == *(args + 1))
-                   {
-                     s++;
-                     args++;
-                     continue;
-                   }
-                 break;
-               }
-             args++;
-             continue;
-             
-           case 'K':           /* DEST operand completer (optional), must
-                                  match previous dest if specified.  */
-           case '&':           /* DEST instruction completer */
-           case ';':           /* DEST instruction completer, must be xyz */
-             {
-               int w,x,y,z;
-               static int last_h;
-
-               w = x = y = z = 0;
-
-               /* Parse the completer.  */
-               s_reset = s;
-               while ((!full_opcode_match || *args == 'K')
-                      && *s != '\0' && *s != ' ' && *s != ',')
-                 {
-                   if (*s == 'w')
-                     w++;
-                   else if (*s == 'x')
-                     x++;
-                   else if (*s == 'y')
-                     y++;
-                   else if (*s == 'z')
-                     z++;
-                   else
-                     {
-                       insn_error = "Invalid dest specification";
-                       break;
-                     }
-                   s++;
-                 }
-
-               if (insn_error)
-                 continue;
-
-               /* Each completer can only appear once.  */
-               if (w > 1 || x > 1 || y > 1 || z > 1)
-                 {
-                   insn_error = "Invalid dest specification";
-                   continue;
-                 }
-
-               /* If this is the opcode completer, then we must insert
-                  the appropriate value into the insn.  */
-               if (*args == '&')
-                 {
-                   /* Not strictly in the specs, but requested by users.  */
-                   if (w == 0 && x == 0 && y == 0 && z == 0)
-                     w = x = y = z = 1;
-
-                   ip->insn_opcode |= ((w << 21) | (x << 24)
-                                       | (y << 23) | (z << 22));
-                   last_h = (w << 3) | (x << 0) | (y << 1) | (z << 2);
-                 }
-               else if (*args == ';')
-                 {
-                   /* This implicitly has the .xyz completer.  */
-                   if (w == 0 && x == 0 && y == 0 && z == 0)
-                     x = y = z = 1;
-
-                   if (w != 0 || x != 1 || y != 1 || z != 1)
-                     {
-                       insn_error = "Invalid dest specification";
-                       continue;
-                     }
-
-                   last_h = (w << 3) | (x << 0) | (y << 1) | (z << 2);
-                 }
-               else
-                 {
-                   int temp;
-
-                   /* This is the operand completer, make sure it matches
-                      the previous opcode completer.  */
-                   temp = (w << 3) | (x << 0) | (y << 1) | (z << 2);
-                   if (temp && temp != last_h)
-                     {
-                       insn_error = "DEST field in operand does not match DEST field in instruction";
-                       continue;
-                     }
-
-                 }
-       
-               continue;
-             }
-
-           case 'J':           /* vu0 I register */
-             if (s[0] == 'I')
-               s += 1;
-             else
-               insn_error = "operand `I' expected";
-             continue;
-       
-           case 'Q':           /* vu0 Q register */
-             if (s[0] == 'Q')
-               s += 1;
-             else
-               insn_error = "operand `Q' expected";
-             continue;
-
-           case 'X':           /* vu0 R register */
-             if (s[0] == 'R')
-               s += 1;
-             else
-               insn_error = "operand `R' expected";
-             continue;
-
-           case 'U':           /* vu0 ACC register */
-             if (s[0] == 'A' && s[1] == 'C' && s[2] == 'C')
-               s += 3;
-             else
-               insn_error = "operand `ACC' expected";
-             continue;
-
-           case 'O':
-             my_getSmallExpression (&imm_expr, s);
-             imm_reloc = BFD_RELOC_MIPS15_S3;
-             s = expr_end;
-             continue;
-           /* end-sanitize-r5900 */
-
-           case 'k':           /* cache code */
-           case 'h':           /* prefx code */
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > 31)
+             if ((unsigned long) imm_expr.X_add_number > 31)
                {
                  as_warn (_("Invalid value for `%s' (%lu)"),
                           ip->insn_mo->name,
@@ -7637,9 +7139,9 @@ mips_ip (str, ip)
                {
                  as_warn (_("Illegal break code (%ld)"),
                           (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number &= 0x3ff;
+                 imm_expr.X_add_number &= OP_MASK_CODE;
                }
-             ip->insn_opcode |= imm_expr.X_add_number << 16;
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -7651,51 +7153,62 @@ mips_ip (str, ip)
                {
                  as_warn (_("Illegal lower break code (%ld)"),
                           (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number &= 0x3ff;
+                 imm_expr.X_add_number &= OP_MASK_CODE2;
                }
-             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE2;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
-           case 'B':           /* syscall code */
+           case 'B':           /* 20-bit syscall/break code.  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned) imm_expr.X_add_number > 0xfffff)
-               as_warn (_("Illegal syscall code (%ld)"),
+             if ((unsigned) imm_expr.X_add_number > OP_MASK_CODE20)
+               as_warn (_("Illegal 20-bit code (%ld)"),
                         (long) imm_expr.X_add_number);
-             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE20;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
             case 'C':           /* Coprocessor code */
-              my_getExpression (&imm_expr, s);
+             my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-              if ((unsigned long) imm_expr.X_add_number >= (1<<25))
+             if ((unsigned long) imm_expr.X_add_number >= (1<<25))
                {
-                  as_warn (_("Coproccesor code > 25 bits (%ld)"),
+                 as_warn (_("Coproccesor code > 25 bits (%ld)"),
                           (long) imm_expr.X_add_number);
-                  imm_expr.X_add_number &= ((1<<25) - 1);
+                 imm_expr.X_add_number &= ((1<<25) - 1);
                }
-              ip->insn_opcode |= imm_expr.X_add_number;
-              imm_expr.X_op = O_absent;
-              s = expr_end;
-              continue;
+             ip->insn_opcode |= imm_expr.X_add_number;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case 'J':           /* 19-bit wait code.  */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned) imm_expr.X_add_number > OP_MASK_CODE19)
+               as_warn (_("Illegal 19-bit code (%ld)"),
+                        (long) imm_expr.X_add_number);
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE19;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
 
            case 'P':           /* Performance register */
-              my_getExpression (&imm_expr, s);
+             my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
+             if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                {
-                  as_warn (_("Invalidate performance regster (%ld)"),
+                 as_warn (_("Invalid performance register (%ld)"),
                           (long) imm_expr.X_add_number);
-                  imm_expr.X_add_number &= 1;
+                 imm_expr.X_add_number &= OP_MASK_PERFREG;
                }
-              ip->insn_opcode |= (imm_expr.X_add_number << 1);
-              imm_expr.X_op = O_absent;
-              s = expr_end;
-              continue;
+             ip->insn_opcode |= (imm_expr.X_add_number << OP_SH_PERFREG);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
 
            case 'b':           /* base register */
            case 'd':           /* destination register */
@@ -7708,21 +7221,12 @@ mips_ip (str, ip)
            case 'G':           /* coprocessor destination register */
            case 'x':           /* ignore register name */
            case 'z':           /* must be zero register */
+           case 'U':           /* destination register (clo/clz).  */
              s_reset = s;
              if (s[0] == '$')
                {
-                 /* start-sanitize-r5900 */
-                 /* Allow "$viNN" as coprocessor register name */
-                 if (mips_5900
-                     && *args == 'G'
-                     && s[1] == 'v'
-                     && s[2] == 'i')
-                   {
-                     s += 2;
-                   }
-                 /* end-sanitize-r5900 */
 
-                 if (isdigit (s[1]))
+                 if (isdigit ((unsigned char) s[1]))
                    {
                      ++s;
                      regno = 0;
@@ -7732,7 +7236,7 @@ mips_ip (str, ip)
                          regno += *s - '0';
                          ++s;
                        }
-                     while (isdigit (*s));
+                     while (isdigit ((unsigned char) *s));
                      if (regno > 31)
                        as_bad (_("Invalid register number (%d)"), regno);
                    }
@@ -7773,28 +7277,27 @@ mips_ip (str, ip)
                      else if (itbl_have_entries)
                        {
                          char *p, *n;
-                         int r;
+                         unsigned long r;
 
-                         p = s+1;      /* advance past '$' */
+                         p = s + 1;    /* advance past '$' */
                          n = itbl_get_field (&p);  /* n is name */
 
-                         /* See if this is a register defined in an 
-                            itbl entry */
-                         r = itbl_get_reg_val (n);
-                         if (r)
+                         /* See if this is a register defined in an
+                            itbl entry.  */
+                         if (itbl_get_reg_val (n, &r))
                            {
                              /* Get_field advances to the start of
                                 the next field, so we need to back
-                                rack to the end of the last field. */
-                             if (p) 
+                                rack to the end of the last field.  */
+                             if (p)
                                s = p - 1;
-                             else 
-                               s = strchr (s,'\0');
+                             else
+                               s = strchr (s, '\0');
                              regno = r;
                            }
                          else
                            goto notreg;
-                         }
+                       }
                      else
                        goto notreg;
                    }
@@ -7819,24 +7322,28 @@ mips_ip (str, ip)
                  if (c == 'z' && regno != 0)
                    break;
 
-       /* Now that we have assembled one operand, we use the args string 
-        * to figure out where it goes in the instruction. */
+       /* Now that we have assembled one operand, we use the args string
+        * to figure out where it goes in the instruction.  */
                  switch (c)
                    {
                    case 'r':
                    case 's':
                    case 'v':
                    case 'b':
-                     ip->insn_opcode |= regno << 21;
+                     ip->insn_opcode |= regno << OP_SH_RS;
                      break;
                    case 'd':
                    case 'G':
-                     ip->insn_opcode |= regno << 11;
+                     ip->insn_opcode |= regno << OP_SH_RD;
+                     break;
+                   case 'U':
+                     ip->insn_opcode |= regno << OP_SH_RD;
+                     ip->insn_opcode |= regno << OP_SH_RT;
                      break;
                    case 'w':
                    case 't':
                    case 'E':
-                     ip->insn_opcode |= regno << 16;
+                     ip->insn_opcode |= regno << OP_SH_RT;
                      break;
                    case 'x':
                      /* This case exists because on the r3000 trunc
@@ -7867,10 +7374,10 @@ mips_ip (str, ip)
                {
                case 'r':
                case 'v':
-                 ip->insn_opcode |= lastregno << 21;
+                 ip->insn_opcode |= lastregno << OP_SH_RS;
                  continue;
                case 'w':
-                 ip->insn_opcode |= lastregno << 16;
+                 ip->insn_opcode |= lastregno << OP_SH_RT;
                  continue;
                }
              break;
@@ -7881,18 +7388,8 @@ mips_ip (str, ip)
            case 'R':           /* floating point source register */
            case 'V':
            case 'W':
-           /* start-sanitize-r5900 */
-           case '1':           /* vu0 fp reg position 1 */
-           case '2':           /* vu0 fp reg position 2 */
-           case '3':           /* vu0 fp reg position 3 */
-           case '4':           /* vu0 int reg position 1 */
-           case '5':           /* vu0 int reg position 2 */
-           case '6':           /* vu0 int reg position 3 */
-           case '7':           /* vu0 fp reg with ftf modifier */
-           case '8':           /* vu0 fp reg with fsf modifier */
-           /* end-sanitize-r5900 */
              s_reset = s;
-             if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
+             if (s[0] == '$' && s[1] == 'f' && isdigit ((unsigned char) s[2]))
                {
                  s += 2;
                  regno = 0;
@@ -7902,13 +7399,13 @@ mips_ip (str, ip)
                      regno += *s - '0';
                      ++s;
                    }
-                 while (isdigit (*s));
+                 while (isdigit ((unsigned char) *s));
 
                  if (regno > 31)
                    as_bad (_("Invalid float register number (%d)"), regno);
 
                  if ((regno & 1) != 0
-                     && mips_opts.isa < 3
+                     && HAVE_32BIT_FPRS
                      && ! (strcmp (str, "mtc1") == 0
                            || strcmp (str, "mfc1") == 0
                            || strcmp (str, "lwc1") == 0
@@ -7933,125 +7430,31 @@ mips_ip (str, ip)
                  switch (c)
                    {
                    case 'D':
-                     ip->insn_opcode |= regno << 6;
+                     ip->insn_opcode |= regno << OP_SH_FD;
                      break;
                    case 'V':
                    case 'S':
-                     ip->insn_opcode |= regno << 11;
+                     ip->insn_opcode |= regno << OP_SH_FS;
                      break;
                    case 'W':
                    case 'T':
-                     ip->insn_opcode |= regno << 16;
+                     ip->insn_opcode |= regno << OP_SH_FT;
                      break;
                    case 'R':
-                     ip->insn_opcode |= regno << 21;
-                     break;
-                   }
-                 lastregno = regno;
-                 continue;
-               }
-
-             /* start-sanitize-r5900 */
-             /* Handle vf and vi regsiters for vu0.  Handle optional
-                 `$' prefix. */
-             
-             if ((s[0] == 'v'
-                  && (s[1] == 'f' || s[1] == 'i')
-                  && isdigit (s[2]))
-                 ||
-                 (s[0] == '$'
-                  && s[1] == 'v'
-                  && (s[2] == 'f' || s[2] == 'i')
-                  && isdigit (s[3])))
-               {
-                 if(s[0] == '$')
-                   ++s;
-                 s += 2;
-                 regno = 0;
-                 do
-                   {
-                     regno *= 10;
-                     regno += *s - '0';
-                     ++s;
-                   }
-                 while (isdigit (*s));
-
-                 if (regno > 31)
-                   as_bad (_("Invalid vu0 register number (%d)"), regno);
-
-                 c = *args;
-
-                 if (c == '7' || c == '8')
-                   {
-                     int value;
-
-                     switch (*s)
-                       {
-                       case 'w':
-                         value = 3;
-                         s++;
-                         ip->insn_opcode |= value << (c == '7' ? 23 : 21);
-                         break;
-                       case 'x':
-                         value = 0;
-                         s++;
-                         ip->insn_opcode |= value << (c == '7' ? 23 : 21);
-                         break;
-                       case 'y':
-                         value = 1;
-                         s++;
-                         ip->insn_opcode |= value << (c == '7' ? 23 : 21);
-                         break;
-                       case 'z':
-                         value = 2;
-                         s++;
-                         ip->insn_opcode |= value << (c == '7' ? 23 : 21);
-                         break;
-                       default:
-                         as_bad (_("Invalid FSF/FTF specification"));
-                       }
-                   }
-
-                 if (*s == ' ')
-                   s++;
-                 if (args[1] != *s)
-                   {
-                     if (c == 'V' || c == 'W')
-                       {
-                         regno = lastregno;
-                         s = s_reset;
-                         args++;
-                       }
-                   }
-                 switch (c)
-                   {
-                   case '1':
-                   case '4':
-                   case '7':
-                     ip->insn_opcode |= regno << 16;
-                     break;
-                   case '2':
-                   case '5':
-                   case '8':
-                     ip->insn_opcode |= regno << 11;
-                     break;
-                   case '3':
-                   case '6':
-                     ip->insn_opcode |= regno << 6;
+                     ip->insn_opcode |= regno << OP_SH_FR;
                      break;
                    }
                  lastregno = regno;
                  continue;
                }
-             /* end-sanitize-r5900 */
 
              switch (*args++)
                {
                case 'V':
-                 ip->insn_opcode |= lastregno << 11;
+                 ip->insn_opcode |= lastregno << OP_SH_FS;
                  continue;
                case 'W':
-                 ip->insn_opcode |= lastregno << 16;
+                 ip->insn_opcode |= lastregno << OP_SH_FT;
                  continue;
                }
              break;
@@ -8076,6 +7479,7 @@ mips_ip (str, ip)
            case 'l':
              {
                int f64;
+               int using_gprs;
                char *save_in;
                char *err;
                unsigned char temp[8];
@@ -8109,9 +7513,15 @@ mips_ip (str, ip)
                    .lit4 inline easily; we need to put .lit8
                    somewhere in the data segment, and using .lit8
                    permits the linker to eventually combine identical
-                   .lit8 entries).  */
+                   .lit8 entries).
+
+                   The code below needs to know whether the target register
+                   is 32 or 64 bits wide.  It relies on the fact 'f' and
+                   'F' are used with GPR-based instructions and 'l' and
+                   'L' are used with FPR-based instructions.  */
 
                f64 = *args == 'F' || *args == 'L';
+               using_gprs = *args == 'F' || *args == 'f';
 
                save_in = input_line_pointer;
                input_line_pointer = s;
@@ -8126,7 +7536,7 @@ mips_ip (str, ip)
                    length = f64 ? 8 : 4;
                  }
 
-               assert (length == (f64 ? 8 : 4));
+               assert (length == (unsigned) (f64 ? 8 : 4));
 
                if (*args == 'f'
                    || (*args == 'l'
@@ -8143,18 +7553,25 @@ mips_ip (str, ip)
                      imm_expr.X_add_number = bfd_getb32 (temp);
                  }
                else if (length > 4
+                        && ! mips_disable_float_construction
+                        /* Constants can only be constructed in GPRs and
+                           copied to FPRs if the GPRs are at least as wide
+                           as the FPRs.  Force the constant into memory if
+                           we are using 64-bit FPRs but the GPRs are only
+                           32 bits wide.  */
+                        && (using_gprs
+                            || ! (HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
                         && ((temp[0] == 0 && temp[1] == 0)
                             || (temp[2] == 0 && temp[3] == 0))
                         && ((temp[4] == 0 && temp[5] == 0)
                             || (temp[6] == 0 && temp[7] == 0)))
                  {
-                   /* The value is simple enough to load with a
-                       couple of instructions.  In mips1 mode, set
-                       imm_expr to the high order 32 bits and
-                       offset_expr to the low order 32 bits.
-                       Otherwise, set imm_expr to the entire 64 bit
-                       constant.  */
-                   if (mips_opts.isa < 3)
+                   /* The value is simple enough to load with a couple of
+                       instructions.  If using 32-bit registers, set
+                       imm_expr to the high order 32 bits and offset_expr to
+                       the low order 32 bits.  Otherwise, set imm_expr to
+                       the entire 64 bit constant.  */
+                   if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
                      {
                        imm_expr.X_op = O_constant;
                        offset_expr.X_op = O_constant;
@@ -8212,11 +7629,15 @@ mips_ip (str, ip)
                      default: /* unused default case avoids warnings.  */
                      case 'L':
                        newname = RDATA_SECTION_NAME;
-                       if (USE_GLOBAL_POINTER_OPT && g_switch_value >= 8)
+                       if ((USE_GLOBAL_POINTER_OPT && g_switch_value >= 8)
+                           || mips_pic == EMBEDDED_PIC)
                          newname = ".lit8";
                        break;
                      case 'F':
-                       newname = RDATA_SECTION_NAME;
+                       if (mips_pic == EMBEDDED_PIC)
+                         newname = ".lit8";
+                       else
+                         newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
                        assert (!USE_GLOBAL_POINTER_OPT
@@ -8262,14 +7683,18 @@ mips_ip (str, ip)
            case 'j':           /* 16 bit signed immediate */
              imm_reloc = BFD_RELOC_LO16;
              c = my_getSmallExpression (&imm_expr, s);
-             if (c != '\0')
+             if (c != S_EX_NONE)
                {
-                 if (c != 'l')
+                 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 == 'h')
+                     else if (c == S_EX_HIGHEST)
+                         imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+                     else if (c == S_EX_HIGHER)
+                         imm_reloc = BFD_RELOC_MIPS_HIGHER;
+                     else if (c == S_EX_HI)
                        {
                          imm_reloc = BFD_RELOC_HI16_S;
                          imm_unmatched_hi = true;
@@ -8282,18 +7707,16 @@ mips_ip (str, ip)
                }
              if (*args == 'i')
                {
-                 if ((c == '\0' && imm_expr.X_op != O_constant)
+                 if ((c == S_EX_NONE && imm_expr.X_op != O_constant)
                      || ((imm_expr.X_add_number < 0
-                           || imm_expr.X_add_number >= 0x10000)
-                          && imm_expr.X_op == O_constant))
+                          || imm_expr.X_add_number >= 0x10000)
+                         && imm_expr.X_op == O_constant))
                    {
                      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
                          !strcmp (insn->name, insn[1].name))
                        break;
-                     if (imm_expr.X_op != O_constant
-                         && imm_expr.X_op != O_big)
-                       insn_error = _("absolute expression required");
-                     else
+                     if (imm_expr.X_op == O_constant
+                         || imm_expr.X_op == O_big)
                        as_bad (_("16 bit expression not in range 0..65535"));
                    }
                }
@@ -8317,22 +7740,20 @@ mips_ip (str, ip)
                    max = 0x8000;
                  else
                    max = 0x10000;
-                 if ((c == '\0' && imm_expr.X_op != O_constant)
+                 if ((c == S_EX_NONE && imm_expr.X_op != O_constant)
                      || ((imm_expr.X_add_number < -0x8000
-                           || imm_expr.X_add_number >= max)
-                          && imm_expr.X_op == O_constant)
+                          || imm_expr.X_add_number >= max)
+                         && imm_expr.X_op == O_constant)
                      || (more
                          && imm_expr.X_add_number < 0
-                         && mips_opts.isa >= 3
+                         && HAVE_64BIT_GPRS
                          && imm_expr.X_unsigned
                          && sizeof (imm_expr.X_add_number) <= 4))
                    {
                      if (more)
                        break;
-                     if (imm_expr.X_op != O_constant
-                         && imm_expr.X_op != O_big)
-                       insn_error = _("absolute expression required");
-                     else
+                     if (imm_expr.X_op == O_constant
+                         || imm_expr.X_op == O_big)
                        as_bad (_("16 bit expression not in range -32768..32767"));
                    }
                }
@@ -8353,24 +7774,24 @@ mips_ip (str, ip)
                 fashion is that the macro function doesn't expect to
                 see anything which can be handled in a single
                 constant instruction.  */
-             if (c == 0
+             if (c == S_EX_NONE
                  && (offset_expr.X_op != O_constant
                      || offset_expr.X_add_number >= 0x8000
                      || offset_expr.X_add_number < -0x8000)
                  && (mips_pic != EMBEDDED_PIC
                      || offset_expr.X_op != O_subtract
-                     || now_seg != text_section
-                     || (S_GET_SEGMENT (offset_expr.X_op_symbol)
-                         != text_section)))
+                     || (S_GET_SEGMENT (offset_expr.X_add_symbol)
+                         != S_GET_SEGMENT (offset_expr.X_op_symbol))))
                break;
 
-             offset_reloc = BFD_RELOC_LO16;
-             if (c == 'h' || c == 'H')
+             if (c == S_EX_HI)
                {
-                 assert (offset_expr.X_op == O_constant);
+                 if (offset_expr.X_op != O_constant)
+                   break;
                  offset_expr.X_add_number =
                    (offset_expr.X_add_number >> 16) & 0xffff;
                }
+             offset_reloc = BFD_RELOC_LO16;
              s = expr_end;
              continue;
 
@@ -8383,14 +7804,16 @@ mips_ip (str, ip)
            case 'u':           /* upper 16 bits */
              c = my_getSmallExpression (&imm_expr, s);
              imm_reloc = BFD_RELOC_LO16;
-             if (c)
+             if (c != S_EX_NONE)
                {
-                 if (c != 'l')
+                 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 == 'h')
+                     else if (c == S_EX_HIGHEST)
+                         imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+                     else if (c == S_EX_HI)
                        {
                          imm_reloc = BFD_RELOC_HI16_S;
                          imm_unmatched_hi = true;
@@ -8426,45 +7849,37 @@ mips_ip (str, ip)
                  regno += *s - '0';
                  ++s;
                }
-             while (isdigit (*s));
+             while (isdigit ((unsigned char) *s));
              if (regno > 7)
                as_bad (_("invalid condition code register $fcc%d"), regno);
              if (*args == 'N')
                ip->insn_opcode |= regno << OP_SH_BCC;
              else
                ip->insn_opcode |= regno << OP_SH_CCC;
-              continue;
-
-             /* start-sanitize-cygnus */
-           case 'e':           /* must be at least one digit */
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > (unsigned long) OP_MASK_VECBYTE)
-               {
-                 as_bad (_("bad byte vector index (%ld)"),
-                          (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number = imm_expr.X_add_number;
-               }
-             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECBYTE;
-             imm_expr.X_op = O_absent;
-             s = expr_end;
              continue;
 
-           case '%':
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > (unsigned long) OP_MASK_VECALIGN)
+           case 'H':
+             if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+               s += 2;
+             if (isdigit ((unsigned char) *s))
                {
-                 as_bad (_("bad byte vector index (%ld)"),
-                          (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number = imm_expr.X_add_number;
+                 c = 0;
+                 do
+                   {
+                     c *= 10;
+                     c += *s - '0';
+                     ++s;
+                   }
+                 while (isdigit ((unsigned char) *s));
                }
-             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECALIGN;
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+             else
+               c = 8; /* Invalid sel value.  */
+
+             if (c > 7)
+               as_bad (_("invalid coprocessor sub-selection value (0-7)"));
+             ip->insn_opcode |= c;
              continue;
 
-             /* end-sanitize-cygnus */
            default:
              as_bad (_("bad char = '%c'\n"), *args);
              internalError ();
@@ -8477,8 +7892,11 @@ mips_ip (str, ip)
        {
          ++insn;
          s = argsStart;
+         insn_error = _("illegal operands");
          continue;
        }
+      if (save_c)
+       *(--s) = save_c;
       insn_error = _("illegal operands");
       return;
     }
@@ -8509,7 +7927,7 @@ mips16_ip (str, ip)
   mips16_small = false;
   mips16_ext = false;
 
-  for (s = str; islower (*s); ++s)
+  for (s = str; islower ((unsigned char) *s); ++s)
     ;
   switch (*s)
     {
@@ -8642,7 +8060,7 @@ mips16_ip (str, ip)
              if (s[0] != '$')
                break;
              s_reset = s;
-             if (isdigit (s[1]))
+             if (isdigit ((unsigned char) s[1]))
                {
                  ++s;
                  regno = 0;
@@ -8652,7 +8070,7 @@ mips16_ip (str, ip)
                      regno += *s - '0';
                      ++s;
                    }
-                 while (isdigit (*s));
+                 while (isdigit ((unsigned char) *s));
                  if (regno > 31)
                    {
                      as_bad (_("invalid register number (%d)"), regno);
@@ -8923,7 +8341,7 @@ mips16_ip (str, ip)
                        ++s;
                      }
                    reg1 = 0;
-                   while (isdigit (*s))
+                   while (isdigit ((unsigned char) *s))
                      {
                        reg1 *= 10;
                        reg1 += *s - '0';
@@ -8950,7 +8368,7 @@ mips16_ip (str, ip)
                              }
                          }
                        reg2 = 0;
-                       while (isdigit (*s))
+                       while (isdigit ((unsigned char) *s))
                          {
                            reg2 *= 10;
                            reg2 += *s - '0';
@@ -9142,7 +8560,8 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
     needext = false;
 
   if (warn && ext && ! needext)
-    as_warn_where (file, line, _("extended operand requested but not required"));
+    as_warn_where (file, line,
+                  _("extended operand requested but not required"));
   if (small && needext)
     as_bad_where (file, line, _("invalid unextended operand value"));
 
@@ -9196,8 +8615,6 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
     }
 }
 \f
-#define LP '('
-#define RP ')'
 
 static int
 my_getSmallExpression (ep, str)
@@ -9205,85 +8622,145 @@ my_getSmallExpression (ep, str)
      char *str;
 {
   char *sp;
-  int c = 0;
+  char *oldstr = str;
+  int c = S_EX_NONE;
 
   if (*str == ' ')
     str++;
-  if (*str == LP
-      || (*str == '%' &&
-         ((str[1] == 'h' && str[2] == 'i')
-          || (str[1] == 'H' && str[2] == 'I')
-          || (str[1] == 'l' && str[2] == 'o'))
-         && str[3] == LP))
-    {
-      if (*str == LP)
-       c = 0;
-      else
-       {
-         c = str[1];
-         str += 3;
-       }
+  if (*str == '(')
+    c = S_EX_NONE;
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'l'
+          && tolower(str[2]) == 'o'
+          && str[3] == '(')
+    {
+      c = S_EX_LO;
+      str += sizeof ("%lo(") - 2;
+    }
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'h'
+          && tolower(str[2]) == 'i'
+          && str[3] == '(')
+    {
+      c = S_EX_HI;
+      str += sizeof ("%hi(") - 2;
+    }
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'h'
+          && tolower(str[2]) == 'i'
+          && tolower(str[3]) == 'g'
+          && tolower(str[4]) == 'h'
+          && tolower(str[5]) == 'e'
+          && tolower(str[6]) == 'r'
+          && str[7] == '(')
+    {
+      c = S_EX_HIGHER;
+      str += sizeof ("%higher(") - 2;
+    }
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'h'
+          && tolower(str[2]) == 'i'
+          && tolower(str[3]) == 'g'
+          && tolower(str[4]) == 'h'
+          && tolower(str[5]) == 'e'
+          && tolower(str[6]) == 's'
+          && tolower(str[7]) == 't'
+          && str[8] == '(')
+    {
+      c = S_EX_HIGHEST;
+      str += sizeof ("%highest(") - 2;
+    }
+/* currently unsupported */
+#if 0
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'g'
+          && tolower(str[2]) == 'p'
+          && tolower(str[3]) == '_'
+          && tolower(str[4]) == 'r'
+          && tolower(str[5]) == 'e'
+          && tolower(str[6]) == 'l'
+          && str[7] == '(')
+    {
+      c = S_EX_GPREL;
+      str += sizeof ("%gp_rel(") - 2;
+    }
+  else if (str[0] == '%'
+          && tolower(str[1]) == 'n'
+          && tolower(str[2]) == 'e'
+          && tolower(str[3]) == 'g'
+          && str[4] == '(')
+    {
+      c = S_EX_NEG;
+      str += sizeof ("%neg(") - 2;
+    }
+#endif
+  else
+    {
+      my_getExpression (ep, str);
+      return c;
+    }
 
-      /*
-       * A small expression may be followed by a base register.
-       * Scan to the end of this operand, and then back over a possible
-       * base register.  Then scan the small expression up to that
-       * point.  (Based on code in sparc.c...)
-       */
-      for (sp = str; *sp && *sp != ','; sp++)
-       ;
-      if (sp - 4 >= str && sp[-1] == RP)
+  /*
+   * A small expression may be followed by a base register.
+   * Scan to the end of this operand, and then back over a possible
+   * base register.  Then scan the small expression up to that
+   * point.  (Based on code in sparc.c...)
+   */
+  for (sp = str; *sp && *sp != ','; sp++)
+    ;
+  if (sp - 4 >= str && sp[-1] == ')')
+    {
+      if (isdigit ((unsigned char) sp[-2]))
        {
-         if (isdigit (sp[-2]))
+         for (sp -= 3; sp >= str && isdigit ((unsigned char) *sp); sp--)
+           ;
+         if (*sp == '$' && sp > str && sp[-1] == '(')
            {
-             for (sp -= 3; sp >= str && isdigit (*sp); sp--)
-               ;
-             if (*sp == '$' && sp > str && sp[-1] == LP)
-               {
-                 sp--;
-                 goto do_it;
-               }
+             sp--;
+             goto do_it;
            }
-         else if (sp - 5 >= str
-                  && sp[-5] == LP
-                  && sp[-4] == '$'
-                  && ((sp[-3] == 'f' && sp[-2] == 'p')
-                      || (sp[-3] == 's' && sp[-2] == 'p')
-                      || (sp[-3] == 'g' && sp[-2] == 'p')
-                      || (sp[-3] == 'a' && sp[-2] == 't')))
+       }
+      else if (sp - 5 >= str
+              && sp[-5] == '('
+              && sp[-4] == '$'
+              && ((sp[-3] == 'f' && sp[-2] == 'p')
+                  || (sp[-3] == 's' && sp[-2] == 'p')
+                  || (sp[-3] == 'g' && sp[-2] == 'p')
+                  || (sp[-3] == 'a' && sp[-2] == 't')))
+       {
+         sp -= 5;
+       do_it:
+         if (sp == str)
            {
-             sp -= 5;
-           do_it:
-             if (sp == str)
+             /* no expression means zero offset */
+             if (c != S_EX_NONE)
                {
-                 /* no expression means zero offset */
-                 if (c)
-                   {
-                     /* %xx(reg) is an error */
-                     ep->X_op = O_absent;
-                     expr_end = str - 3;
-                   }
-                 else
-                   {
-                     ep->X_op = O_constant;
-                     expr_end = sp;
-                   }
-                 ep->X_add_symbol = NULL;
-                 ep->X_op_symbol = NULL;
-                 ep->X_add_number = 0;
+                 /* %xx(reg) is an error */
+                 ep->X_op = O_absent;
+                 expr_end = oldstr;
                }
              else
                {
-                 *sp = '\0';
-                 my_getExpression (ep, str);
-                 *sp = LP;
+                 ep->X_op = O_constant;
+                 expr_end = sp;
                }
-             return c;
+             ep->X_add_symbol = NULL;
+             ep->X_op_symbol = NULL;
+             ep->X_add_number = 0;
            }
+         else
+           {
+             *sp = '\0';
+             my_getExpression (ep, str);
+             *sp = '(';
+           }
+         return c;
        }
     }
   my_getExpression (ep, str);
-  return c;                    /* => %hi or %lo encountered */
+
+  /* => %highest, %higher, %hi, %lo, %gprel, %neg encountered */
+  return c;
 }
 
 static void
@@ -9292,6 +8769,7 @@ my_getExpression (ep, str)
      char *str;
 {
   char *save_in;
+  valueT val;
 
   save_in = input_line_pointer;
   input_line_pointer = str;
@@ -9307,15 +8785,15 @@ my_getExpression (ep, str)
       && ep->X_op == O_symbol
       && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
       && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
-      && ep->X_add_symbol->sy_frag == frag_now
-      && ep->X_add_symbol->sy_value.X_op == O_constant
-      && ep->X_add_symbol->sy_value.X_add_number == frag_now_fix ())
-    ++ep->X_add_symbol->sy_value.X_add_number;
+      && symbol_get_frag (ep->X_add_symbol) == frag_now
+      && symbol_constant_p (ep->X_add_symbol)
+      && (val = S_GET_VALUE (ep->X_add_symbol)) == frag_now_fix ())
+    S_SET_VALUE (ep->X_add_symbol, val + 1);
 }
 
 /* Turn a string in input_line_pointer into a floating point constant
-   of type type, and store the appropriate bytes in *litP.  The number
-   of LITTLENUMS emitted is stored in *sizeP .  An error message is
+   of type TYPE, and store the appropriate bytes in *LITP.  The number
+   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 
 char *
@@ -9366,7 +8844,7 @@ md_atof (type, litP, sizeP)
          litP += 2;
        }
     }
-     
+
   return NULL;
 }
 
@@ -9382,9 +8860,10 @@ md_number_to_chars (buf, val, n)
     number_to_chars_littleendian (buf, val, n);
 }
 \f
-CONST char *md_shortopts = "O::g::G:";
+CONST char *md_shortopts = "nO::g::G:";
 
-struct option md_longopts[] = {
+struct option md_longopts[] =
+{
 #define OPTION_MIPS1 (OPTION_MD_BASE + 1)
   {"mips0", no_argument, NULL, OPTION_MIPS1},
   {"mips1", no_argument, NULL, OPTION_MIPS1},
@@ -9398,103 +8877,80 @@ struct option md_longopts[] = {
   {"mcpu", required_argument, NULL, OPTION_MCPU},
 #define OPTION_MEMBEDDED_PIC (OPTION_MD_BASE + 6)
   {"membedded-pic", no_argument, NULL, OPTION_MEMBEDDED_PIC},
-#define OPTION_TRAP (OPTION_MD_BASE + 9)
+#define OPTION_TRAP (OPTION_MD_BASE + 7)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
-#define OPTION_BREAK (OPTION_MD_BASE + 10)
+#define OPTION_BREAK (OPTION_MD_BASE + 8)
   {"break", no_argument, NULL, OPTION_BREAK},
   {"no-trap", no_argument, NULL, OPTION_BREAK},
-#define OPTION_EB (OPTION_MD_BASE + 11)
+#define OPTION_EB (OPTION_MD_BASE + 9)
   {"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL (OPTION_MD_BASE + 12)
+#define OPTION_EL (OPTION_MD_BASE + 10)
   {"EL", no_argument, NULL, OPTION_EL},
-#define OPTION_M4650 (OPTION_MD_BASE + 13)
+#define OPTION_M4650 (OPTION_MD_BASE + 11)
   {"m4650", no_argument, NULL, OPTION_M4650},
-#define OPTION_NO_M4650 (OPTION_MD_BASE + 14)
+#define OPTION_NO_M4650 (OPTION_MD_BASE + 12)
   {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-#define OPTION_M4010 (OPTION_MD_BASE + 15)
+#define OPTION_M4010 (OPTION_MD_BASE + 13)
   {"m4010", no_argument, NULL, OPTION_M4010},
-#define OPTION_NO_M4010 (OPTION_MD_BASE + 16)
+#define OPTION_NO_M4010 (OPTION_MD_BASE + 14)
   {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-#define OPTION_M4100 (OPTION_MD_BASE + 17)
+#define OPTION_M4100 (OPTION_MD_BASE + 15)
   {"m4100", no_argument, NULL, OPTION_M4100},
-#define OPTION_NO_M4100 (OPTION_MD_BASE + 18)
+#define OPTION_NO_M4100 (OPTION_MD_BASE + 16)
   {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-#define OPTION_MIPS16 (OPTION_MD_BASE + 22)
+#define OPTION_MIPS16 (OPTION_MD_BASE + 17)
   {"mips16", no_argument, NULL, OPTION_MIPS16},
-#define OPTION_NO_MIPS16 (OPTION_MD_BASE + 23)
+#define OPTION_NO_MIPS16 (OPTION_MD_BASE + 18)
   {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-  /* start-sanitize-r5900 */
-#define OPTION_M5900 (OPTION_MD_BASE + 24)
-  {"m5900", no_argument, NULL, OPTION_M5900},
-#define OPTION_NO_M5900 (OPTION_MD_BASE + 25)
-  {"no-m5900", no_argument, NULL, OPTION_NO_M5900},
-  /* end-sanitize-r5900 */
-#define OPTION_M3900 (OPTION_MD_BASE + 26)
+#define OPTION_M3900 (OPTION_MD_BASE + 19)
   {"m3900", no_argument, NULL, OPTION_M3900},
-#define OPTION_NO_M3900 (OPTION_MD_BASE + 27)
+#define OPTION_NO_M3900 (OPTION_MD_BASE + 20)
   {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
-
-  /* start-sanitize-tx19 */
-  {"m1900", no_argument, NULL, OPTION_M3900},
-  {"no-m1900", no_argument, NULL, OPTION_NO_M3900},
-  /* end-sanitize-tx19 */
-
-  /* start-sanitize-cygnus */
-#define OPTION_M5400 (OPTION_MD_BASE + 28)
-  {"m5400", no_argument, NULL, OPTION_M5400},
-#define OPTION_NO_M5400 (OPTION_MD_BASE + 29)
-  {"no-m5400", no_argument, NULL, OPTION_NO_M5400},
-
-  /* end-sanitize-cygnus */
-  /* start-sanitize-tx49 */
-#define OPTION_M4900 (OPTION_MD_BASE + 30)
-  {"m4900", no_argument, NULL, OPTION_M4900},
-#define OPTION_NO_M4900 (OPTION_MD_BASE + 31)
-  {"no-m4900", no_argument, NULL, OPTION_NO_M4900},
-
-  /* end-sanitize-tx49 */
-  /* start-sanitize-vr4320 */
-#define OPTION_M4320 (OPTION_MD_BASE + 32)
-  {"m4320", no_argument, NULL, OPTION_M4320},
-#define OPTION_NO_M4320 (OPTION_MD_BASE + 33)
-  {"no-m4320", no_argument, NULL, OPTION_NO_M4320},
-
-  /* end-sanitize-vr4320 */
-  /* start-sanitize-branchbug4011 */
-#define OPTION_FIX_4011_BRANCH_BUG (OPTION_MD_BASE + 34)
-  {"fix-4011-branch-bug", no_argument, NULL, OPTION_FIX_4011_BRANCH_BUG},
-#define OPTION_NO_FIX_4011_BRANCH_BUG (OPTION_MD_BASE + 35)
-  {"no-fix-4011-branch-bug", no_argument, NULL, OPTION_NO_FIX_4011_BRANCH_BUG},
-
-  /* end-sanitize-branchbug4011 */
-  /* start-sanitize-vr4xxx */
-#define OPTION_M4121 (OPTION_MD_BASE + 36)
-  {"m4121", no_argument, NULL, OPTION_M4121},
-#define OPTION_NO_M4121 (OPTION_MD_BASE + 37)
-  {"no-m4121", no_argument, NULL, OPTION_NO_M4121},
-
-  /* end-sanitize-vr4xxx */
-#define OPTION_MABI (OPTION_MD_BASE + 38)
+#define OPTION_MABI (OPTION_MD_BASE + 21)
   {"mabi", required_argument, NULL, OPTION_MABI},
-
-#define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
-#define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
-#define OPTION_XGOT (OPTION_MD_BASE + 19)
-#define OPTION_32 (OPTION_MD_BASE + 20)
-#define OPTION_64 (OPTION_MD_BASE + 21)
+#define OPTION_M7000_HILO_FIX (OPTION_MD_BASE + 22)
+  {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
+#define OPTION_NO_M7000_HILO_FIX (OPTION_MD_BASE + 23)
+  {"no-fix-7000", no_argument, NULL, OPTION_NO_M7000_HILO_FIX},
+#define OPTION_GP32 (OPTION_MD_BASE + 24)
+  {"mgp32", no_argument, NULL, OPTION_GP32},
+#define OPTION_GP64 (OPTION_MD_BASE + 25)
+  {"mgp64", no_argument, NULL, OPTION_GP64},
+#define OPTION_CONSTRUCT_FLOATS (OPTION_MD_BASE + 26)
+  {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
+#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MD_BASE + 27)
+  {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
+#define OPTION_MIPS32 (OPTION_MD_BASE + 28)
+  {"mips32", no_argument, NULL, OPTION_MIPS32},
+#define OPTION_MIPS5 (OPTION_MD_BASE + 29)
+  {"mips5", no_argument, NULL, OPTION_MIPS5},
+#define OPTION_MIPS64 (OPTION_MD_BASE + 30)
+  {"mips64", no_argument, NULL, OPTION_MIPS64},
+#define OPTION_MARCH (OPTION_MD_BASE + 31)
+  {"march", required_argument, NULL, OPTION_MARCH},
+#define OPTION_MTUNE (OPTION_MD_BASE + 32)
+  {"mtune", required_argument, NULL, OPTION_MTUNE},
+#define OPTION_FP32 (OPTION_MD_BASE + 33)
+  {"mfp32", no_argument, NULL, OPTION_FP32},
 #ifdef OBJ_ELF
-  {"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
-  {"xgot", no_argument, NULL, OPTION_XGOT},
+#define OPTION_ELF_BASE    (OPTION_MD_BASE + 35)
+#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
+#define OPTION_NON_SHARED  (OPTION_ELF_BASE + 1)
+#define OPTION_XGOT        (OPTION_ELF_BASE + 2)
+#define OPTION_32         (OPTION_ELF_BASE + 3)
+#define OPTION_64          (OPTION_ELF_BASE + 4)
+  {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-  {"non_shared", no_argument, NULL, OPTION_NON_SHARED},
-  {"32", no_argument, NULL, OPTION_32},
-  {"64", no_argument, NULL, OPTION_64},
+  {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
+  {"xgot",        no_argument, NULL, OPTION_XGOT},
+  {"32",          no_argument, NULL, OPTION_32},
+  {"64",          no_argument, NULL, OPTION_64},
 #endif
 
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
@@ -9503,6 +8959,14 @@ md_parse_option (c, arg)
 {
   switch (c)
     {
+    case OPTION_CONSTRUCT_FLOATS:
+      mips_disable_float_construction = 0;
+      break;
+
+    case OPTION_NO_CONSTRUCT_FLOATS:
+      mips_disable_float_construction = 1;
+      break;
+
     case OPTION_TRAP:
       mips_trap = 1;
       break;
@@ -9519,6 +8983,10 @@ md_parse_option (c, arg)
       target_big_endian = 0;
       break;
 
+    case 'n':
+      warn_nops = 1;
+      break;
+
     case 'O':
       if (arg && arg[1] == '0')
        mips_optimize = 1;
@@ -9539,253 +9007,135 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_MIPS1:
-      mips_opts.isa = 1;
+      mips_opts.isa = ISA_MIPS1;
       break;
 
     case OPTION_MIPS2:
-      mips_opts.isa = 2;
+      mips_opts.isa = ISA_MIPS2;
       break;
 
     case OPTION_MIPS3:
-      mips_opts.isa = 3;
+      mips_opts.isa = ISA_MIPS3;
       break;
 
     case OPTION_MIPS4:
-      mips_opts.isa = 4;
+      mips_opts.isa = ISA_MIPS4;
       break;
 
-    case OPTION_MCPU:
-      {
-       char *p;
-
-       /* Identify the processor type */
-       p = arg;
-       if (strcmp (p, "default") == 0
-           || strcmp (p, "DEFAULT") == 0)
-         mips_cpu = -1;
-       else
-         {
-           int sv = 0;
-
-           /* We need to cope with the various "vr" prefixes for the 4300
-              processor.  */
-           if (*p == 'v' || *p == 'V')
-             {
-               sv = 1;
-               p++;
-             }
-
-           if (*p == 'r' || *p == 'R')
-             p++;
-
-           mips_cpu = -1;
-           switch (*p)
-             {
-             case '1':
-               if (strcmp (p, "10000") == 0
-                   || strcmp (p, "10k") == 0
-                   || strcmp (p, "10K") == 0)
-                 mips_cpu = 10000;
-                /* start-sanitize-tx19 */
-                else if (strcmp (p, "1900") == 0)
-                  mips_cpu = 3900;
-                /* end-sanitize-tx19 */
-               break;
-
-             case '2':
-               if (strcmp (p, "2000") == 0
-                   || strcmp (p, "2k") == 0
-                   || strcmp (p, "2K") == 0)
-                 mips_cpu = 2000;
-               break;
-
-             case '3':
-               if (strcmp (p, "3000") == 0
-                   || strcmp (p, "3k") == 0
-                   || strcmp (p, "3K") == 0)
-                 mips_cpu = 3000;
-                else if (strcmp (p, "3900") == 0)
-                  mips_cpu = 3900;
-               break;
-
-             case '4':
-               if (strcmp (p, "4000") == 0
-                   || strcmp (p, "4k") == 0
-                   || strcmp (p, "4K") == 0)
-                 mips_cpu = 4000;
-               else if (strcmp (p, "4100") == 0)
-                    mips_cpu = 4100;
-               /* start-sanitize-vr4xxx */
-               else if (strcmp (p, "4111") == 0)
-                    mips_cpu = 4111;
-               else if (strcmp (p, "4121") == 0)
-                    mips_cpu = 4121;
-               /* end-sanitize-vr4xxx */
-               else if (strcmp (p, "4300") == 0)
-                 mips_cpu = 4300;
-               /* start-sanitize-vr4320 */
-               else if (strcmp (p, "4320") == 0)
-                 mips_cpu = 4320;
-               /* end-sanitize-vr4320 */
-               else if (strcmp (p, "4400") == 0)
-                 mips_cpu = 4400;
-               else if (strcmp (p, "4600") == 0)
-                 mips_cpu = 4600;
-               else if (strcmp (p, "4650") == 0)
-                   mips_cpu = 4650;
-                /* start-sanitize-tx49 */
-               else if (strcmp (p, "4900") == 0)
-                 mips_cpu = 4900;
-                /* end-sanitize-tx49 */
-               else if (strcmp (p, "4010") == 0)
-                  mips_cpu = 4010;
-               break;
+    case OPTION_MIPS5:
+      mips_opts.isa = ISA_MIPS5;
+      break;
 
-             case '5':
-               if (strcmp (p, "5000") == 0
-                   || strcmp (p, "5k") == 0
-                   || strcmp (p, "5K") == 0)
-                 mips_cpu = 5000;
-                /* start-sanitize-cygnus */
-                else if (strcmp (p, "5400") == 0)
-                  mips_cpu = 5400;
-                /* end-sanitize-cygnus */
-                /* start-sanitize-r5900 */
-                else if (strcmp (p, "5900") == 0)
-                  mips_cpu = 5900;
-                /* end-sanitize-r5900 */
-               break;
+    case OPTION_MIPS32:
+      mips_opts.isa = ISA_MIPS32;
+      break;
 
-             case '6':
-               if (strcmp (p, "6000") == 0
-                   || strcmp (p, "6k") == 0
-                   || strcmp (p, "6K") == 0)
-                 mips_cpu = 6000;
-               break;
+    case OPTION_MIPS64:
+      mips_opts.isa = ISA_MIPS64;
+      break;
 
-             case '8':
-               if (strcmp (p, "8000") == 0
-                   || strcmp (p, "8k") == 0
-                   || strcmp (p, "8K") == 0)
-                 mips_cpu = 8000;
-               break;
+    case OPTION_MTUNE:
+    case OPTION_MARCH:
+    case OPTION_MCPU:
+      {
+       int cpu = CPU_UNKNOWN;
 
-             case 'o':
-               if (strcmp (p, "orion") == 0)
-                 mips_cpu = 4600;
-               break;
-             }
+       /* Identify the processor type.  */
+       if (strcasecmp (arg, "default") != 0)
+         {
+           const struct mips_cpu_info *ci;
 
-           if (sv
-               && (mips_cpu != 4300
-                   && mips_cpu != 4100
-                   /* start-sanitize-vr4xxx */
-                   && mips_cpu != 4111
-                   && mips_cpu != 4121
-                   /* end-sanitize-vr4xxx */
-                   /* start-sanitize-vr4320 */
-                   && mips_cpu != 4320
-                   /* end-sanitize-vr4320 */
-                   /* start-sanitize-cygnus */
-                   && mips_cpu != 5400
-                   /* end-sanitize-cygnus */
-                   && mips_cpu != 5000))
+           ci = mips_cpu_info_from_name (arg);
+           if (ci == NULL || ci->is_isa)
              {
-               as_bad (_("ignoring invalid leading 'v' in -mcpu=%s switch"), arg);
-               return 0;
+               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;
+         }
 
-           if (mips_cpu == -1)
-             {
-               as_bad (_("invalid architecture -mcpu=%s"), arg);
-               return 0;
-             }
+       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;
          }
       }
       break;
 
     case OPTION_M4650:
-      mips_4650 = 1;
+      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;
       break;
 
     case OPTION_NO_M4650:
-      mips_4650 = 0;
       break;
 
     case OPTION_M4010:
-      mips_4010 = 1;
+      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;
       break;
 
     case OPTION_NO_M4010:
-      mips_4010 = 0;
       break;
 
     case OPTION_M4100:
-      mips_4100 = 1;
+      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;
       break;
 
     case OPTION_NO_M4100:
-      mips_4100 = 0;
       break;
 
-      /* start-sanitize-vr4xxx */
-    case OPTION_M4121:
-      mips_4121 = 1;
-      break;
-
-    case OPTION_NO_M4121:
-      mips_4121 = 0;
-      break;
-
-      /* end-sanitize-vr4xxx */
-      /* start-sanitize-r5900 */
-    case OPTION_M5900:
-      mips_5900 = 1;
-      break;
-
-    case OPTION_NO_M5900:
-      mips_5900 = 0;
-      break;
-      /* end-sanitize-r5900 */
-
-      /* start-sanitize-vr4320 */
-    case OPTION_M4320:
-      mips_4320 = 1;
-      break;
-
-    case OPTION_NO_M4320:
-      mips_4320 = 0;
-      break;
-
-      /* end-sanitize-vr4320 */
-      /* start-sanitize-cygnus */
-    case OPTION_M5400:
-      mips_5400 = 1;
-      break;
-
-    case OPTION_NO_M5400:
-      mips_5400 = 0;
-      break;
-
-      /* end-sanitize-cygnus */
     case OPTION_M3900:
-      mips_3900 = 1;
-      break;
-      
-    case OPTION_NO_M3900:
-      mips_3900 = 0;
+      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;
       break;
 
-      /* start-sanitize-tx49 */
-    case OPTION_M4900:
-      mips_4900 = 1;
-      break;
-      
-    case OPTION_NO_M4900:
-      mips_4900 = 0;
+    case OPTION_NO_M3900:
       break;
 
-      /* end-sanitize-tx49 */
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
       mips_no_prev_insn (false);
@@ -9806,6 +9156,7 @@ md_parse_option (c, arg)
       g_switch_value = 0x7fffffff;
       break;
 
+#ifdef OBJ_ELF
       /* When generating ELF code, we permit -KPIC and -call_shared to
         select SVR4_PIC, and -non_shared to select no PIC.  This is
         intended to be compatible with Irix 5.  */
@@ -9839,6 +9190,7 @@ md_parse_option (c, arg)
     case OPTION_XGOT:
       mips_big_got = 1;
       break;
+#endif /* OBJ_ELF */
 
     case 'G':
       if (! USE_GLOBAL_POINTER_OPT)
@@ -9856,6 +9208,7 @@ md_parse_option (c, arg)
       g_switch_seen = 1;
       break;
 
+#ifdef OBJ_ELF
       /* The -32 and -64 options tell the assembler to output the 32
          bit or the 64 bit MIPS ELF format.  */
     case OPTION_32:
@@ -9868,8 +9221,14 @@ md_parse_option (c, arg)
 
        list = bfd_target_list ();
        for (l = list; *l != NULL; l++)
+#ifdef TE_TMIPS
+         /* This is traditional mips */
+         if (strcmp (*l, "elf64-tradbigmips") == 0
+             || strcmp (*l, "elf64-tradlittlemips") == 0)
+#else
          if (strcmp (*l, "elf64-bigmips") == 0
              || strcmp (*l, "elf64-littlemips") == 0)
+#endif
            break;
        if (*l == NULL)
          as_fatal (_("No compiled in support for 64 bit object file format"));
@@ -9877,25 +9236,56 @@ md_parse_option (c, arg)
        mips_64 = 1;
       }
       break;
+#endif /* OBJ_ELF */
+
+    case OPTION_GP32:
+      mips_gp32 = 1;
+      mips_64 = 0;
+
+      /* We deliberately don't allow "-gp32" to set the MIPS_32BITMODE
+        flag in object files because to do so would make it
+        impossible to link with libraries compiled without "-gp32".
+        This is unnecessarily restrictive.
 
-      /* start-sanitize-branchbug4011 */
-    case OPTION_FIX_4011_BRANCH_BUG:
-      mips_fix_4011_branch_bug = 1;
+        We could solve this problem by adding "-gp32" multilibs to
+        gcc, but to set this flag before gcc is built with such
+        multilibs will break too many systems.  */
+
+#if 0
+      mips_32bitmode = 1;
+#endif
       break;
 
-    case OPTION_NO_FIX_4011_BRANCH_BUG:
-      mips_fix_4011_branch_bug = 0;
+    case OPTION_GP64:
+      mips_gp32 = 0;
+      mips_64 = 1;
+#if 0
+      mips_32bitmode = 0;
+#endif
       break;
 
-      /* end-sanitize-branchbug4011 */
+    case OPTION_FP32:
+      mips_fp32 = 1;
+      break;
 
     case OPTION_MABI:
-      if (strcmp (arg,"32") == 0
-         || strcmp (arg,"n32") == 0
-         || strcmp (arg,"64") == 0
-         || strcmp (arg,"o64") == 0
-         || strcmp (arg,"eabi") == 0)
-       mips_abi_string = arg;
+      if (strcmp (arg, "32") == 0
+         || strcmp (arg, "n32") == 0
+         || strcmp (arg, "64") == 0
+         || strcmp (arg, "o64") == 0
+         || strcmp (arg, "eabi") == 0)
+       {
+         mips_abi_string = arg;
+         mips_32bit_abi = (strcmp (arg, "32") == 0);
+       }
+      break;
+
+    case OPTION_M7000_HILO_FIX:
+      mips_7000_hilo_fix = true;
+      break;
+
+    case OPTION_NO_M7000_HILO_FIX:
+      mips_7000_hilo_fix = false;
       break;
 
     default:
@@ -9905,49 +9295,114 @@ md_parse_option (c, arg)
   return 1;
 }
 
+static void
+show (stream, string, col_p, first_p)
+     FILE *stream;
+     char *string;
+     int *col_p;
+     int *first_p;
+{
+  if (*first_p)
+    {
+      fprintf (stream, "%24s", "");
+      *col_p = 24;
+    }
+  else
+    {
+      fprintf (stream, ", ");
+      *col_p += 2;
+    }
+
+  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;
 {
-  fprintf(stream, _("\
+  int column, first;
+
+  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 uneeded NOPs or swap branches\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, _("\
+  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\
--mcpu=vr4300           generate code for vr4300\n\
--mcpu=vr4100           generate code for vr4100\n\
--m4650                 permit R4650 instructions\n\
--no-m4650              do not permit R4650 instructions\n\
--m4010                 permit R4010 instructions\n\
--no-m4010              do not permit R4010 instructions\n\
--m4100                  permit VR4100 instructions\n\
--no-m4100              do not permit VR4100 instructions\n"));
-  /* start-sanitize-vr4xxx */
-  fprintf(stream, _("\
--mcpu=vr4111           generate code for vr4111\n"));
-  fprintf(stream, _("\
--mcpu=vr4121           generate code for vr4121\n\
--m4121                  permit VR4121 instructions\n\
--no-m4121              do not permit VR4121 instructions\n"));
-  /* end-sanitize-vr4xxx */
-  fprintf(stream, _("\
+-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;
+
+  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, "mips32-4k", &column, &first);
+  show (stream, "sb-1", &column, &first);
+  fputc ('\n', stream);
+
+  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, _("\
+  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, _("\
+  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\
@@ -9961,7 +9416,7 @@ mips_init_after_args ()
 {
   /* initialize opcodes */
   bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
-  mips_opcodes = (struct mips_opcode*) mips_builtin_opcodes;
+  mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
 }
 
 long
@@ -9981,37 +9436,6 @@ md_pcrel_from (fixP)
   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
-/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
-   reloc for a cons.  We could use the definition there, except that
-   we want to handle 64 bit relocs specially.  */
-
-void
-cons_fix_new_mips (frag, where, nbytes, exp)
-     fragS *frag;
-     int where;
-     unsigned int nbytes;
-     expressionS *exp;
-{
-#ifndef OBJ_ELF
-  /* If we are assembling in 32 bit mode, turn an 8 byte reloc into a
-     4 byte reloc.  */
-  if (nbytes == 8 && ! mips_64)
-    {
-      if (target_big_endian)
-       where += 4;
-      nbytes = 4;
-    }
-#endif
-
-  if (nbytes != 2 && nbytes != 4 && nbytes != 8)
-    as_bad (_("Unsupported reloc size %d"), nbytes);
-
-  fix_new_exp (frag_now, where, (int) nbytes, exp, 0,
-              (nbytes == 2
-               ? BFD_RELOC_16
-               : (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64)));
-}
-
 /* This is called before the symbol table is processed.  In order to
    work with gcc when using mips-tfile, we must keep all local labels.
    However, in other cases, we want to discard them.  If we were
@@ -10103,9 +9527,12 @@ mips_frob_file ()
          if (f != NULL)
            break;
 
+#if 0 /* GCC code motion plus incomplete dead code elimination
+        can leave a %hi without a %lo.  */
          if (pass == 1)
            as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
                           _("Unmatched %%hi reloc"));
+#endif
        }
     }
 }
@@ -10117,6 +9544,7 @@ mips_frob_file ()
    fixup requires the special reloc.  */
 #define SWITCH_TABLE(fixp) \
   ((fixp)->fx_r_type == BFD_RELOC_32 \
+   && OUTPUT_FLAVOR != bfd_target_elf_flavour \
    && (fixp)->fx_addsy != NULL \
    && (fixp)->fx_subsy != NULL \
    && S_GET_SEGMENT ((fixp)->fx_addsy) == text_section \
@@ -10126,7 +9554,6 @@ mips_frob_file ()
    relocations, in case the linker has to relax a call.  We also need
    to keep relocations for switch table entries.  */
 
-/*ARGSUSED*/
 int
 mips_force_relocation (fixp)
      fixS *fixp;
@@ -10150,7 +9577,8 @@ md_apply_fix (fixP, valueP)
      valueT *valueP;
 {
   unsigned char *buf;
-  long insn, value;
+  long insn;
+  valueT value;
 
   assert (fixP->fx_size == 4
          || fixP->fx_r_type == BFD_RELOC_16
@@ -10163,18 +9591,84 @@ md_apply_fix (fixP, valueP)
   /* If we aren't adjusting this fixup to be against the section
      symbol, we need to adjust the value.  */
 #ifdef OBJ_ELF
-  if (fixP->fx_addsy != NULL
-      && OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16
-         || S_IS_WEAK (fixP->fx_addsy)))
-    {
-      value -= S_GET_VALUE (fixP->fx_addsy);
-      if (value != 0 && ! fixP->fx_pcrel)
+  if (fixP->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    {
+      if (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16
+         || ((S_IS_WEAK (fixP->fx_addsy)
+              || S_IS_EXTERN (fixP->fx_addsy))
+             && !S_IS_COMMON (fixP->fx_addsy))
+         || (symbol_used_in_reloc_p (fixP->fx_addsy)
+             && (((bfd_get_section_flags (stdoutput,
+                                          S_GET_SEGMENT (fixP->fx_addsy))
+                   & SEC_LINK_ONCE) != 0)
+                 || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
+                              ".gnu.linkonce",
+                              sizeof (".gnu.linkonce") - 1))))
+
+       {
+         valueT symval = S_GET_VALUE (fixP->fx_addsy);
+         value -= symval;
+         if (value != 0
+             && ! fixP->fx_pcrel
+             && fixP->fx_r_type != BFD_RELOC_MIPS_GPREL)
+           {
+             /* In this case, the bfd_install_relocation routine will
+                incorrectly add the symbol value back in.  We just want
+                the addend to appear in the object file.  */
+             value -= symval;
+
+             /* Make sure the addend is still non-zero.  If it became zero
+                after the last operation, set it to a spurious value and
+                subtract the same value from the object file's contents.  */
+             if (value == 0)
+               {
+                 value = 8;
+
+                 /* The in-place addends for LO16 relocations are signed;
+                    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,
+                                              target_big_endian);
+
+                     /* MASK has bits set where the relocation should go.
+                        FIELD is -value, shifted into the appropriate place
+                        for this relocation.  */
+                     mask = 1 << (howto->bitsize - 1);
+                     mask = (((mask - 1) << 1) | 1) << howto->bitpos;
+                     field = (-value >> howto->rightshift) << howto->bitpos;
+
+                     bfd_put_bits ((field & mask) | (contents & ~mask),
+                                   fixP->fx_frag->fr_literal + fixP->fx_where,
+                                   fixP->fx_size * 8,
+                                   target_big_endian);
+                   }
+               }
+           }
+       }
+
+      /* This code was generated using trial and error and so is
+        fragile and not trustworthy.  If you change it, you should
+        rerun the elf-rel, elf-rel2, and empic testcases and ensure
+        they still pass.  */
+      if (fixP->fx_pcrel || fixP->fx_subsy != NULL)
        {
-         /* In this case, the bfd_install_relocation routine will
-             incorrectly add the symbol value back in.  We just want
-             the addend to appear in the object file.  */
-         value -= S_GET_VALUE (fixP->fx_addsy);
+         value += fixP->fx_frag->fr_address + fixP->fx_where;
+
+         /* BFD's REL handling, for MIPS, is _very_ weird.
+            This gives the right results, but it can't possibly
+            be the way things are supposed to work.  */
+         if (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2
+             || S_GET_SEGMENT (fixP->fx_addsy) != undefined_section)
+           value += fixP->fx_frag->fr_address + fixP->fx_where;
        }
     }
 #endif
@@ -10199,9 +9693,6 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
     case BFD_RELOC_MIPS16_GPREL:
-    /* start-sanitize-r5900 */
-    case BFD_RELOC_MIPS15_S3:
-    /* end-sanitize-r5900 */
       if (fixP->fx_pcrel)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Invalid PC relative reloc"));
@@ -10218,7 +9709,12 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_HI16_S:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+         && !fixP->fx_done
+         && value != 0)
+       break;
+      if (fixP->fx_addsy
+         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        {
          /* For an external symbol adjust by the address to make it
             pcrel_offset.  We use the address of the RELLO reloc
@@ -10226,9 +9722,7 @@ md_apply_fix (fixP, valueP)
          value += (fixP->fx_next->fx_frag->fr_address
                    + fixP->fx_next->fx_where);
        }
-      if (value & 0x8000)
-       value += 0x10000;
-      value >>= 16;
+      value = ((value + 0x8000) >> 16) & 0xffff;
       buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
        buf += 2;
@@ -10238,7 +9732,12 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_LO16:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+         && !fixP->fx_done
+         && value != 0)
+       break;
+      if (fixP->fx_addsy
+         && (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        value += fixP->fx_frag->fr_address + fixP->fx_where;
       buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
@@ -10275,6 +9774,7 @@ md_apply_fix (fixP, valueP)
        }
       break;
 
+    case BFD_RELOC_RVA:
     case BFD_RELOC_32:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
@@ -10301,7 +9801,7 @@ md_apply_fix (fixP, valueP)
         up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
       if (fixP->fx_done)
        {
-         if (value < -0x8000 || value > 0x7fff)
+         if (value + 0x8000 > 0xffff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relocation overflow"));
          buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
@@ -10319,8 +9819,17 @@ md_apply_fix (fixP, valueP)
        */
       if ((value & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("Branch to odd address (%lx)"), value);
-      value >>= 2;
+                     _("Branch to odd address (%lx)"), (long) value);
+
+      if (!fixP->fx_done && value != 0)
+       break;
+      /* If 'value' is zero, the remaining reloc code won't actually
+        do the store, so it must be done here.  This is probably
+        a bug somewhere.  */
+      if (!fixP->fx_done)
+       value -= fixP->fx_frag->fr_address + fixP->fx_where;
+
+      value = (offsetT) value >> 2;
 
       /* update old instruction data */
       buf = (unsigned char *) (fixP->fx_where + fixP->fx_frag->fr_literal);
@@ -10329,7 +9838,7 @@ md_apply_fix (fixP, valueP)
       else
        insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
 
-      if (value >= -0x8000 && value < 0x8000)
+      if (value + 0x8000 <= 0xffff)
        insn |= value & 0xffff;
       else
        {
@@ -10507,7 +10016,7 @@ mips_align (to, fill, label)
   if (label != NULL)
     {
       assert (S_GET_SEGMENT (label) == now_seg);
-      label->sy_frag = frag_now;
+      symbol_set_frag (label, frag_now);
       S_SET_VALUE (label, (valueT) frag_now_fix ());
     }
 }
@@ -10517,7 +10026,7 @@ mips_align (to, fill, label)
 
 static void
 s_align (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   register int temp;
   register long temp_fill;
@@ -10622,7 +10131,7 @@ s_change_sec (sec)
                                      | SEC_RELOC
                                      | SEC_DATA));
              if (strcmp (TARGET_OS, "elf") != 0)
-               bfd_set_section_alignment (stdoutput, seg, 4);
+               record_alignment (seg, 4);
            }
          demand_empty_rest_of_line ();
        }
@@ -10644,7 +10153,7 @@ s_change_sec (sec)
                                     SEC_ALLOC | SEC_LOAD | SEC_RELOC
                                     | SEC_DATA);
              if (strcmp (TARGET_OS, "elf") != 0)
-               bfd_set_section_alignment (stdoutput, seg, 4);
+               record_alignment (seg, 4);
            }
          demand_empty_rest_of_line ();
          break;
@@ -10691,10 +10200,12 @@ s_float_cons (type)
   mips_emit_delays (false);
 
   if (auto_align)
-    if (type == 'd')
-      mips_align (3, 0, label);
-    else
-      mips_align (2, 0, label);
+    {
+      if (type == 'd')
+       mips_align (3, 0, label);
+      else
+       mips_align (2, 0, label);
+    }
 
   mips_clear_insn_labels ();
 
@@ -10709,7 +10220,7 @@ s_float_cons (type)
 
 static void
 s_mips_globl (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *name;
   int c;
@@ -10742,7 +10253,7 @@ s_mips_globl (x)
        flag = BSF_FUNCTION;
     }
 
-  symbolP->bsym->flags |= flag;
+  symbol_get_bfdsym (symbolP)->flags |= flag;
 
   S_SET_EXTERNAL (symbolP);
   demand_empty_rest_of_line ();
@@ -10750,7 +10261,7 @@ s_mips_globl (x)
 
 static void
 s_option (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *opt;
   char c;
@@ -10803,7 +10314,7 @@ static struct mips_option_stack *mips_opts_stack;
 
 static void
 s_mipsset (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   char *name = input_line_pointer, ch;
 
@@ -10818,7 +10329,7 @@ s_mipsset (x)
        {
          /* If we still have pending nops, we can discard them.  The
             usual nop handling will insert any that are still
-            needed. */
+            needed.  */
          prev_nop_frag->fr_fix -= (prev_nop_frag_holds
                                    * (mips_opts.mips16 ? 2 : 4));
          prev_nop_frag = NULL;
@@ -10878,12 +10389,18 @@ s_mipsset (x)
       /* Permit the user to change the ISA on the fly.  Needless to
         say, misuse can cause serious problems.  */
       isa = atoi (name + 4);
-      if (isa == 0)
-       mips_opts.isa = file_mips_isa;
-      else if (isa < 1 || isa > 4)
-       as_bad (_("unknown ISA level"));
-      else
-       mips_opts.isa = isa;
+      switch (isa)
+      {
+      case  0: mips_opts.isa = file_mips_isa;   break;
+      case  1: mips_opts.isa = ISA_MIPS1;       break;
+      case  2: mips_opts.isa = ISA_MIPS2;       break;
+      case  3: mips_opts.isa = ISA_MIPS3;       break;
+      case  4: mips_opts.isa = ISA_MIPS4;       break;
+      case  5: mips_opts.isa = ISA_MIPS5;       break;
+      case 32: mips_opts.isa = ISA_MIPS32;      break;
+      case 64: mips_opts.isa = ISA_MIPS64;      break;
+      default: as_bad (_("unknown ISA level")); break;
+      }
     }
   else if (strcmp (name, "autoextend") == 0)
     mips_opts.noautoextend = 0;
@@ -10939,7 +10456,7 @@ s_mipsset (x)
 
 static void
 s_abicalls (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   mips_pic = SVR4_PIC;
   if (USE_GLOBAL_POINTER_OPT)
@@ -10964,7 +10481,7 @@ s_abicalls (ignore)
 
 static void
 s_cpload (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   expressionS ex;
   int icnt = 0;
@@ -10986,7 +10503,7 @@ s_cpload (ignore)
   ex.X_add_number = 0;
 
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
-  ex.X_add_symbol->bsym->flags |= BSF_OBJECT;
+  symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
   macro_build_lui ((char *) NULL, &icnt, &ex, GP);
   macro_build ((char *) NULL, &icnt, &ex, "addiu", "t,r,j", GP, GP,
@@ -11004,7 +10521,7 @@ s_cpload (ignore)
 
 static void
 s_cprestore (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   expressionS ex;
   int icnt = 0;
@@ -11024,9 +10541,7 @@ s_cprestore (ignore)
   ex.X_add_number = mips_cprestore_offset;
 
   macro_build ((char *) NULL, &icnt, &ex,
-              ((bfd_arch_bits_per_address (stdoutput) == 32
-                || mips_opts.isa < 3)
-               ? "sw" : "sd"),
+              HAVE_32BIT_ADDRESSES ? "sw" : "sd",
               "t,o(b)", GP, (int) BFD_RELOC_LO16, SP);
 
   demand_empty_rest_of_line ();
@@ -11037,7 +10552,7 @@ s_cprestore (ignore)
 
 static void
 s_gpword (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *label;
   expressionS ex;
@@ -11077,7 +10592,7 @@ s_gpword (ignore)
 
 static void
 s_cpadd (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   int icnt = 0;
   int reg;
@@ -11092,12 +10607,10 @@ s_cpadd (ignore)
   /* Add $gp to the register named as an argument.  */
   reg = tc_get_register (0);
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-              ((bfd_arch_bits_per_address (stdoutput) == 32
-                || mips_opts.isa < 3)
-               ? "addu" : "daddu"),
+              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
               "d,v,t", reg, reg, GP);
 
-  demand_empty_rest_of_line ();  
+  demand_empty_rest_of_line ();
 }
 
 /* Handle the .insn pseudo-op.  This marks instruction labels in
@@ -11111,7 +10624,7 @@ s_cpadd (ignore)
 
 static void
 s_insn (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (mips_opts.mips16)
     mips16_mark_labels ();
@@ -11140,7 +10653,7 @@ s_mips_stab (type)
 
 static void
 s_mips_weakext (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   int c;
@@ -11164,13 +10677,13 @@ s_mips_weakext (ignore)
          ignore_rest_of_line ();
          return;
        }
-      
+
       if (*input_line_pointer == ',')
        {
          ++input_line_pointer;
          SKIP_WHITESPACE ();
        }
-      
+
       expression (&exp);
       if (exp.X_op != O_symbol)
        {
@@ -11178,7 +10691,7 @@ s_mips_weakext (ignore)
          ignore_rest_of_line();
          return;
        }
-      symbolP->sy_value = exp;
+      symbol_set_value_expression (symbolP, &exp);
     }
 
   demand_empty_rest_of_line ();
@@ -11290,15 +10803,16 @@ nopic_need_relax (sym, before_relaxing)
       else if ((! S_IS_DEFINED (sym) || S_IS_COMMON (sym))
               && (0
 #ifndef NO_ECOFF_DEBUGGING
-                  || (sym->ecoff_extern_size != 0
-                      && sym->ecoff_extern_size <= g_switch_value)
+                  || (symbol_get_obj (sym)->ecoff_extern_size != 0
+                      && (symbol_get_obj (sym)->ecoff_extern_size
+                          <= g_switch_value))
 #endif
                   /* We must defer this decision until after the whole
                      file has been read, since there might be a .extern
                      after the first use of this symbol.  */
                   || (before_relaxing
 #ifndef NO_ECOFF_DEBUGGING
-                      && sym->ecoff_extern_size == 0
+                      && symbol_get_obj (sym)->ecoff_extern_size == 0
 #endif
                       && S_GET_VALUE (sym) == 0)
                   || (S_GET_VALUE (sym) != 0
@@ -11312,7 +10826,9 @@ nopic_need_relax (sym, before_relaxing)
          assert (strcmp (segname, ".lit8") != 0
                  && strcmp (segname, ".lit4") != 0);
          change = (strcmp (segname, ".sdata") != 0
-                   && strcmp (segname, ".sbss") != 0);
+                   && strcmp (segname, ".sbss") != 0
+                   && strncmp (segname, ".sdata.", 7) != 0
+                   && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
        }
       return change;
     }
@@ -11335,6 +10851,7 @@ mips16_extended_frag (fragp, sec, stretch)
   offsetT val;
   int mintiny, maxtiny;
   segT symsec;
+  fragS *sym_frag;
 
   if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
     return 0;
@@ -11368,26 +10885,9 @@ mips16_extended_frag (fragp, sec, stretch)
       maxtiny = (1 << (op->nbits - 1)) - 1;
     }
 
-  /* We can't call S_GET_VALUE here, because we don't want to lock in
-     a particular frag address.  */
-  if (fragp->fr_symbol->sy_value.X_op == O_constant)
-    {
-      val = (fragp->fr_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_frag->fr_address);
-      symsec = S_GET_SEGMENT (fragp->fr_symbol);
-    }
-  else if (fragp->fr_symbol->sy_value.X_op == O_symbol
-          && (fragp->fr_symbol->sy_value.X_add_symbol->sy_value.X_op
-              == O_constant))
-    {
-      val = (fragp->fr_symbol->sy_value.X_add_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_value.X_add_symbol->sy_frag->fr_address
-            + fragp->fr_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_frag->fr_address);
-      symsec = S_GET_SEGMENT (fragp->fr_symbol->sy_value.X_add_symbol);
-    }
-  else
-    return 1;
+  sym_frag = symbol_get_frag (fragp->fr_symbol);
+  val = S_GET_VALUE (fragp->fr_symbol);
+  symsec = S_GET_SEGMENT (fragp->fr_symbol);
 
   if (op->pcrel)
     {
@@ -11406,6 +10906,7 @@ mips16_extended_frag (fragp, sec, stretch)
        }
       else
        {
+         /* Must have been called from md_estimate_size_before_relax.  */
          if (symsec != sec)
            {
              fragp->fr_subtype =
@@ -11418,15 +10919,22 @@ mips16_extended_frag (fragp, sec, stretch)
 
              return 1;
            }
+         if (fragp != sym_frag && sym_frag->fr_address == 0)
+           /* Assume non-extended on the first relaxation pass.
+              The address we have calculated will be bogus if this is
+              a forward branch to another frag, as the forward frag
+              will have fr_address == 0.  */
+           return 0;
        }
 
       /* In this case, we know for sure that the symbol fragment is in
-        the same section.  If the fr_address of the symbol fragment
-        is greater then the address of this fragment we want to add
+        the same section.  If the relax_marker of the symbol fragment
+        differs from the relax_marker of this fragment, we have not
+        yet adjusted the symbol fragment fr_address.  We want to add
         in STRETCH in order to get a better estimate of the address.
         This particularly matters because of the shift bits.  */
       if (stretch != 0
-         && fragp->fr_symbol->sy_frag->fr_address >= fragp->fr_address)
+         && sym_frag->relax_marker != fragp->relax_marker)
        {
          fragS *f;
 
@@ -11436,9 +10944,7 @@ mips16_extended_frag (fragp, sec, stretch)
              This doesn't handle the fr_subtype field, which specifies
              a maximum number of bytes to skip when doing an
              alignment.  */
-         for (f = fragp;
-              f != NULL && f != fragp->fr_symbol->sy_frag;
-              f = f->fr_next)
+         for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
            {
              if (f->fr_type == rs_align || f->fr_type == rs_align_code)
                {
@@ -11468,7 +10974,7 @@ mips16_extended_frag (fragp, sec, stretch)
 
          /* If we are currently assuming that this frag should be
             extended, then, the current address is two bytes
-            higher. */
+            higher.  */
          if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
            addr += 2;
 
@@ -11537,13 +11043,13 @@ mips16_extended_frag (fragp, sec, stretch)
    encoded in the subtype information.  For the mips16, we have to
    decide whether we are using an extended opcode or not.  */
 
-/*ARGSUSED*/
 int
 md_estimate_size_before_relax (fragp, segtype)
      fragS *fragp;
      asection *segtype;
 {
-  int change;
+  int change = 0;
+  boolean linkonce = false;
 
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     {
@@ -11571,14 +11077,14 @@ md_estimate_size_before_relax (fragp, segtype)
       sym = fragp->fr_symbol;
 
       /* Handle the case of a symbol equated to another symbol.  */
-      while (sym->sy_value.X_op == O_symbol
+      while (symbol_equated_p (sym)
             && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
        {
          symbolS *n;
 
          /* It's possible to get a loop here in a badly written
              program.  */
-         n = sym->sy_value.X_add_symbol;
+         n = symbol_get_value_expression (sym)->X_add_symbol;
          if (n == sym)
            break;
          sym = n;
@@ -11586,10 +11092,32 @@ md_estimate_size_before_relax (fragp, segtype)
 
       symsec = S_GET_SEGMENT (sym);
 
+      /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
+      if (symsec != segtype && ! S_IS_LOCAL (sym))
+       {
+         if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
+             != 0)
+           linkonce = true;
+
+         /* The GNU toolchain uses an extension for ELF: a section
+            beginning with the magic string .gnu.linkonce is a linkonce
+            section.  */
+         if (strncmp (segment_name (symsec), ".gnu.linkonce",
+                      sizeof ".gnu.linkonce" - 1) == 0)
+           linkonce = true;
+       }
+
       /* This must duplicate the test in adjust_reloc_syms.  */
       change = (symsec != &bfd_und_section
                && symsec != &bfd_abs_section
-               && ! bfd_is_com_section (symsec));
+               && ! bfd_is_com_section (symsec)
+               && !linkonce
+#ifdef OBJ_ELF
+               /* A global or weak symbol is treated as external.  */
+               && (OUTPUT_FLAVOR == bfd_target_elf_flavour
+                   && ! (S_IS_EXTERN (sym) || S_IS_WEAK (sym)))
+#endif
+               );
     }
   else
     abort ();
@@ -11605,13 +11133,13 @@ md_estimate_size_before_relax (fragp, segtype)
                          + RELAX_RELOC1 (fragp->fr_subtype));
       /* FIXME: This really needs as_warn_where.  */
       if (RELAX_WARN (fragp->fr_subtype))
-       as_warn (_("AT used after \".set noat\" or macro used after \".set nomacro\""));
+       as_warn (_("AT used after \".set noat\" or macro used after "
+                  "\".set nomacro\""));
+
+      return RELAX_NEW (fragp->fr_subtype) - RELAX_OLD (fragp->fr_subtype);
     }
 
-  if (! change)
-    return 0;
-  else
-    return RELAX_NEW (fragp->fr_subtype) - RELAX_OLD (fragp->fr_subtype);
+  return 0;
 }
 
 /* This is called to see whether a reloc against a defined symbol
@@ -11625,6 +11153,12 @@ int
 mips_fix_adjustable (fixp)
      fixS *fixp;
 {
+#ifdef OBJ_ELF
+  /* Prevent all adjustments to global symbols.  */
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+    return 0;
+#endif
   if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
     return 0;
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
@@ -11646,7 +11180,7 @@ mips_fix_adjustable (fixp)
 
 arelent **
 tc_gen_reloc (section, fixp)
-     asection *section;
+     asection *section ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   static arelent *retval[4];
@@ -11656,7 +11190,8 @@ tc_gen_reloc (section, fixp)
   reloc = retval[0] = (arelent *) xmalloc (sizeof (arelent));
   retval[1] = NULL;
 
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   if (mips_pic == EMBEDDED_PIC
@@ -11670,10 +11205,12 @@ tc_gen_reloc (section, fixp)
        as_fatal (_("Double check fx_r_type in tc-mips.c:tc_gen_reloc"));
       fixp->fx_r_type = BFD_RELOC_GPREL32;
     }
+  else if (fixp->fx_pcrel == 0 || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    reloc->addend = fixp->fx_addnumber;
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16)
     {
       /* We use a special addend for an internal RELLO reloc.  */
-      if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
+      if (symbol_section_p (fixp->fx_addsy))
        reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
       else
        reloc->addend = fixp->fx_addnumber + reloc->address;
@@ -11685,7 +11222,7 @@ tc_gen_reloc (section, fixp)
       /* We use a special addend for an internal RELHI reloc.  The
         reloc is relative to the RELLO; adjust the addend
         accordingly.  */
-      if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
+      if (symbol_section_p (fixp->fx_addsy))
        reloc->addend = (fixp->fx_next->fx_frag->fr_address
                         + fixp->fx_next->fx_where
                         - S_GET_VALUE (fixp->fx_subsy));
@@ -11694,8 +11231,6 @@ tc_gen_reloc (section, fixp)
                         + fixp->fx_next->fx_frag->fr_address
                         + fixp->fx_next->fx_where);
     }
-  else if (fixp->fx_pcrel == 0)
-    reloc->addend = fixp->fx_addnumber;
   else
     {
       if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
@@ -11744,7 +11279,8 @@ tc_gen_reloc (section, fixp)
       reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
       reloc2 = retval[1] = (arelent *) xmalloc (sizeof (arelent));
       retval[2] = NULL;
-      reloc2->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc2->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc2->address = (reloc->address
                         + (RELAX_RELOC2 (fixp->fx_frag->fr_subtype)
                            - RELAX_RELOC1 (fixp->fx_frag->fr_subtype)));
@@ -11833,7 +11369,8 @@ tc_gen_reloc (section, fixp)
   /* To support a PC relative reloc when generating embedded PIC code
      for ECOFF, we use a Cygnus extension.  We check for that here to
      make sure that we don't let such a reloc escape normally.  */
-  if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+  if ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
+       || OUTPUT_FLAVOR == bfd_target_elf_flavour)
       && code == BFD_RELOC_16_PCREL_S2
       && mips_pic != EMBEDDED_PIC)
     reloc->howto = NULL;
@@ -11884,7 +11421,7 @@ mips_relax_frag (fragp, stretch)
 
 void
 md_convert_frag (abfd, asec, fragp)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      segT asec;
      fragS *fragp;
 {
@@ -11918,7 +11455,7 @@ md_convert_frag (abfd, asec, fragp)
          ext = false;
        }
 
-      resolve_symbol_value (fragp->fr_symbol, 1);
+      resolve_symbol_value (fragp->fr_symbol);
       val = S_GET_VALUE (fragp->fr_symbol);
       if (op->pcrel)
        {
@@ -12099,41 +11636,79 @@ mips_elf_final_processing ()
   if (mips_pic != NO_PIC)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
 
-  /* Set the MIPS ELF ABI flags. */
-  if (mips_abi_string == 0)
+  /* Set the MIPS ELF ABI flags.  */
+  if (mips_abi_string == NULL)
     ;
-  else if (strcmp (mips_abi_string,"32") == 0)
+  else if (strcmp (mips_abi_string, "32") == 0)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
-  else if (strcmp (mips_abi_string,"o64") == 0)
+  else if (strcmp (mips_abi_string, "o64") == 0)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
-  else if (strcmp (mips_abi_string,"eabi") == 0)
+  else if (strcmp (mips_abi_string, "eabi") == 0)
     {
       if (mips_eabi64)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
     }
+  else if (strcmp (mips_abi_string, "n32") == 0)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
+
+  /* Nothing to do for "64".  */
+
+  if (mips_32bitmode)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
 }
 
 #endif /* OBJ_ELF || OBJ_MAYBE_ELF */
 \f
-typedef struct proc
-  {
-    struct symbol *isym;
-    unsigned long reg_mask;
-    unsigned long reg_offset;
-    unsigned long fpreg_mask;
-    unsigned long fpreg_offset;
-    unsigned long frame_offset;
-    unsigned long frame_reg;
-    unsigned long pc_reg;
-  }
-procS;
+typedef struct proc {
+  symbolS *isym;
+  unsigned long reg_mask;
+  unsigned long reg_offset;
+  unsigned long fpreg_mask;
+  unsigned long fpreg_offset;
+  unsigned long frame_offset;
+  unsigned long frame_reg;
+  unsigned long pc_reg;
+} procS;
 
 static procS cur_proc;
 static procS *cur_proc_ptr;
 static int numprocs;
 
+/* Fill in an rs_align_code fragment.  */
+
+void
+mips_handle_align (fragp)
+     fragS *fragp;
+{
+  if (fragp->fr_type != rs_align_code)
+    return;
+
+  if (mips_opts.mips16)
+    {
+      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 += 1;
+       }
+
+      memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
+      fragp->fr_var = 2;
+    }
+
+  /* For mips32, a nop is a zero, which we trivially get by doing nothing.  */
+}
+
 static void
 md_obj_begin ()
 {
@@ -12144,7 +11719,7 @@ md_obj_end ()
 {
   /* check for premature end, nesting errors, etc */
   if (cur_proc_ptr)
-    as_warn (_("missing `.end' at end of assembly"));
+    as_warn (_("missing .end at end of assembly"));
 }
 
 static long
@@ -12158,14 +11733,14 @@ get_number ()
       ++input_line_pointer;
       negative = 1;
     }
-  if (!isdigit (*input_line_pointer))
+  if (!isdigit ((unsigned char) *input_line_pointer))
     as_bad (_("Expected simple number."));
   if (input_line_pointer[0] == '0')
     {
       if (input_line_pointer[1] == 'x')
        {
          input_line_pointer += 2;
-         while (isxdigit (*input_line_pointer))
+         while (isxdigit ((unsigned char) *input_line_pointer))
            {
              val <<= 4;
              val |= hex_value (*input_line_pointer++);
@@ -12175,7 +11750,7 @@ get_number ()
       else
        {
          ++input_line_pointer;
-         while (isdigit (*input_line_pointer))
+         while (isdigit ((unsigned char) *input_line_pointer))
            {
              val <<= 3;
              val |= *input_line_pointer++ - '0';
@@ -12183,14 +11758,14 @@ get_number ()
          return negative ? -val : val;
        }
     }
-  if (!isdigit (*input_line_pointer))
+  if (!isdigit ((unsigned char) *input_line_pointer))
     {
       printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
              *input_line_pointer, *input_line_pointer);
       as_warn (_("Invalid number"));
       return -1;
     }
-  while (isdigit (*input_line_pointer))
+  while (isdigit ((unsigned char) *input_line_pointer))
     {
       val *= 10;
       val += *input_line_pointer++ - '0';
@@ -12203,7 +11778,7 @@ get_number ()
 
 static void
 s_file (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   int line;
 
@@ -12211,12 +11786,11 @@ s_file (x)
   s_app_file (0);
 }
 
-
 /* The .end directive.  */
 
 static void
 s_mips_end (x)
-     int x;
+     int x ATTRIBUTE_UNUSED;
 {
   symbolS *p;
   int maybe_text;
@@ -12264,9 +11838,7 @@ s_mips_end (x)
   {
     segT saved_seg = now_seg;
     subsegT saved_subseg = now_subseg;
-    fragS *saved_frag = frag_now;
     valueT dot;
-    segT seg;
     expressionS exp;
     char *fragp;
 
@@ -12279,21 +11851,21 @@ s_mips_end (x)
     assert (pdr_seg);
     subseg_set (pdr_seg, 0);
 
-    /* Write the symbol */
+    /* 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);
   }
@@ -12316,7 +11888,8 @@ s_mips_ent (aent)
   if (*input_line_pointer == ',')
     input_line_pointer++;
   SKIP_WHITESPACE ();
-  if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
+  if (isdigit ((unsigned char) *input_line_pointer)
+      || *input_line_pointer == '-')
     number = get_number ();
 
 #ifdef BFD_ASSEMBLER
@@ -12335,7 +11908,7 @@ s_mips_ent (aent)
     as_warn (_(".ent or .aent not in text section."));
 
   if (!aent && cur_proc_ptr)
-    as_warn (_("missing `.end'"));
+    as_warn (_("missing .end"));
 
   if (!aent)
     {
@@ -12344,7 +11917,7 @@ s_mips_ent (aent)
 
       cur_proc_ptr->isym = symbolP;
 
-      symbolP->bsym->flags |= BSF_FUNCTION;
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
 
       numprocs++;
     }
@@ -12353,20 +11926,20 @@ s_mips_ent (aent)
 }
 
 /* The .frame directive. If the mdebug section is present (IRIX 5 native)
-   then ecoff.c (ecoff_directive_frame) is used. For embedded targets, 
+   then ecoff.c (ecoff_directive_frame) is used. For embedded targets,
    s_mips_frame is used so that we can set the PDR information correctly.
-   We can't use the ecoff routines because they make reference to the ecoff 
+   We can't use the ecoff routines because they make reference to the ecoff
    symbol table (in the mdebug section).  */
 
 static void
 s_mips_frame (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
 #ifdef MIPS_STABS_ELF
 
   long val;
 
-  if (cur_proc_ptr ==  (procS *) NULL)
+  if (cur_proc_ptr == (procS *) NULL)
     {
       as_warn (_(".frame outside of .ent"));
       demand_empty_rest_of_line ();
@@ -12394,10 +11967,10 @@ s_mips_frame (ignore)
 #endif /* MIPS_STABS_ELF */
 }
 
-/* The .fmask and .mask directives. If the mdebug section is present 
-   (IRIX 5 native) then ecoff.c (ecoff_directive_mask) is used. For 
+/* The .fmask and .mask directives. If the mdebug section is present
+   (IRIX 5 native) then ecoff.c (ecoff_directive_mask) is used. For
    embedded targets, s_mips_mask is used so that we can set the PDR
-   information correctly. We can't use the ecoff routines because they 
+   information correctly. We can't use the ecoff routines because they
    make reference to the ecoff symbol table (in the mdebug section).  */
 
 static void
@@ -12406,7 +11979,7 @@ s_mips_mask (reg_type)
 {
 #ifdef MIPS_STABS_ELF
   long mask, off;
-  
+
   if (cur_proc_ptr == (procS *) NULL)
     {
       as_warn (_(".mask/.fmask outside of .ent"));
@@ -12465,5 +12038,206 @@ s_loc (x)
 }
 #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.
+
+   Case is ignored in comparison, so put the canonical entry in the
+   appropriate case but everything else in lower case to ease eye pain.  */
+static const struct mips_cpu_info mips_cpu_info_table[] =
+{
+  /* MIPS1 ISA */
+  { "MIPS1",          1,      ISA_MIPS1,      CPU_R3000, },
+  { "mips",           1,      ISA_MIPS1,      CPU_R3000, },
+
+  /* MIPS2 ISA */
+  { "MIPS2",          1,      ISA_MIPS2,      CPU_R6000, },
+
+  /* MIPS3 ISA */
+  { "MIPS3",          1,      ISA_MIPS3,      CPU_R4000, },
+
+  /* MIPS4 ISA */
+  { "MIPS4",          1,      ISA_MIPS4,      CPU_R8000, },
+
+  /* MIPS5 ISA */
+  { "MIPS5",          1,      ISA_MIPS5,      CPU_MIPS5, },
+  { "Generic-MIPS5",  0,      ISA_MIPS5,      CPU_MIPS5, },
 
-  
+  /* MIPS32 ISA */
+  { "MIPS32",         1,      ISA_MIPS32,     CPU_MIPS32, },
+  { "Generic-MIPS32", 0,      ISA_MIPS32,     CPU_MIPS32, },
+
+#if 1
+  /* XXX for now, MIPS64 -> MIPS3 because of history */
+  { "MIPS64",         1,      ISA_MIPS3,      CPU_R4000 }, /* XXX! */
+#else
+  /* MIPS64 ISA */
+  { "MIPS64",         1,      ISA_MIPS64,     CPU_MIPS64 },
+#endif
+  { "mips64isa",      1,      ISA_MIPS64,     CPU_MIPS64 },
+  { "Generic-MIPS64", 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, },
+
+  /* MIPS32 4K CPU */
+  { "MIPS32-4K",      0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4kc",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4km",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4kp",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4kc",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4km",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4kp",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+
+  /* SiByte 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, },
+};
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_name (name)
+     const char *name;
+{
+  int i;
+
+  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]);
+
+  return NULL;
+}
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_isa (isa)
+     int isa;
+{
+  int i;
+
+  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)
+      return (&mips_cpu_info_table[i]);
+
+  return NULL;
+}
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_cpu (cpu)
+     int cpu;
+{
+  int i;
+
+  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]);
+
+  return NULL;
+}
This page took 0.12318 seconds and 4 git commands to generate.