* config/tc-mips.c (macro_build_jalr): Make sure we generate
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 2e4a89034d07b814fe39ef4b2ce61d67166b22fd..c548ddec88075fde5c7e4e138bc370f33c008c60 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
@@ -37,6 +37,7 @@
 
 #include "opcode/mips.h"
 #include "itbl-ops.h"
+#include "dwarf2dbg.h"
 
 #ifdef DEBUG
 #define DBG(x) printf x
@@ -76,12 +77,15 @@ static int mips_output_flavor () { return OUTPUT_FLAVOR; }
 #define ECOFF_DEBUGGING 0
 #endif
 
+int mips_flag_mdebug = -1;
+
 #include "ecoff.h"
 
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 static char *mips_regmask_frag;
 #endif
 
+#define ZERO 0
 #define AT  1
 #define TREG 24
 #define PIC_CALL_REG 25
@@ -125,7 +129,7 @@ enum mips_abi_level
 };
 
 /* MIPS ABI we are using for this output file.  */
-static enum mips_abi_level file_mips_abi = NO_ABI;
+static enum mips_abi_level mips_abi = NO_ABI;
 
 /* This is the set of options which may be modified by the .set
    pseudo-op.  We use a struct so that .set push and .set pop are more
@@ -137,6 +141,11 @@ struct mips_set_options
      if it has not been initialized.  Changed by `.set mipsN', and the
      -mipsN command line option, and the default CPU.  */
   int isa;
+  /* Enabled Application Specific Extensions (ASEs).  These are set to -1
+     if they have not been initialized.  Changed by `.set <asename>', by
+     command line options, and based on the default architecture.  */
+  int ase_mips3d;
+  int ase_mdmx;
   /* Whether we are assembling for the mips16 processor.  0 if we are
      not, 1 if we are, and -1 if the value has not been initialized.
      Changed by `.set mips16' and `.set nomips16', and the -mips16 and
@@ -168,24 +177,21 @@ struct mips_set_options
      is passed but can changed if the assembler code uses .set mipsN.  */
   int gp32;
   int fp32;
-  /* The ABI currently in use. This is changed by .set mipsN to loosen
-     restrictions and doesn't affect the whole file.  */
-  enum mips_abi_level abi;
 };
 
 /* True if -mgp32 was passed.  */
-static int file_mips_gp32 = 0;
+static int file_mips_gp32 = -1;
 
 /* True if -mfp32 was passed.  */
-static int file_mips_fp32 = 0;
+static int file_mips_fp32 = -1;
 
 /* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa field to ISA_UNKNOWN and the mips16 field to
+   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
    -1 to indicate that they have not been initialized.  */
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0, 0, 0, NO_ABI
+  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -197,21 +203,30 @@ unsigned long mips_cprmask[4];
 /* MIPS ISA we are using for this output file.  */
 static int file_mips_isa = ISA_UNKNOWN;
 
-/* The argument of the -mcpu= flag.  Historical for code generation.  */
-static int mips_cpu = CPU_UNKNOWN;
+/* True if -mips16 was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_mips16;
+
+/* True if -mips3d was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_mips3d;
+
+/* True if -mdmx was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_mdmx;
 
 /* The argument of the -march= flag.  The architecture we are assembling.  */
 static int mips_arch = CPU_UNKNOWN;
+static const char *mips_arch_string;
+static const struct mips_cpu_info *mips_arch_info;
 
 /* The argument of the -mtune= flag.  The architecture for which we
    are optimizing.  */
 static int mips_tune = CPU_UNKNOWN;
+static const char *mips_tune_string;
+static const struct mips_cpu_info *mips_tune_info;
 
-/* Whether we should mark the file EABI64 or EABI32.  */
-static int mips_eabi64 = 0;
-
-/* If they asked for mips1 or mips2 and a cpu that is
-   mips3 or greater, then mark the object file 32BITMODE.  */
+/* True when generating 32-bit code for a 64-bit processor.  */
 static int mips_32bitmode = 0;
 
 /* Some ISA's have delay slots for instructions which read or write
@@ -228,6 +243,15 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS3                    \
    )
 
+/* True if the given ABI requires 32-bit registers.  */
+#define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI)
+
+/* Likewise 64-bit registers.  */
+#define ABI_NEEDS_64BIT_REGS(ABI) \
+  ((ABI) == N32_ABI              \
+   || (ABI) == N64_ABI           \
+   || (ABI) == O64_ABI)
+
 /*  Return true if ISA supports 64 bit gp register instructions.  */
 #define ISA_HAS_64BIT_REGS(ISA) (    \
    (ISA) == ISA_MIPS3                \
@@ -237,21 +261,17 @@ static int mips_32bitmode = 0;
    )
 
 #define HAVE_32BIT_GPRS                                   \
-    (mips_opts.gp32                                \
-     || mips_opts.abi == O32_ABI                   \
-     || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+    (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
 
 #define HAVE_32BIT_FPRS                            \
-    (mips_opts.fp32                                \
-     || mips_opts.abi == O32_ABI                   \
-     || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+    (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
 
 #define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
 #define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
 
-#define HAVE_NEWABI (mips_opts.abi == N32_ABI || mips_opts.abi == N64_ABI)
+#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
 
-#define HAVE_64BIT_OBJECTS (mips_opts.abi == N64_ABI)
+#define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
 
 /* We can only have 64bit addresses if the object file format
    supports it.  */
@@ -263,6 +283,18 @@ static int mips_32bitmode = 0;
 
 #define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES)
 
+/* Return true if the given CPU supports the MIPS16 ASE.  */
+#define CPU_HAS_MIPS16(cpu)                            \
+   (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0)
+
+/* Return true if the given CPU supports the MIPS3D ASE.  */
+#define CPU_HAS_MIPS3D(cpu)    ((cpu) == CPU_SB1      \
+                                )
+
+/* Return true if the given CPU supports the MDMX ASE.  */
+#define CPU_HAS_MDMX(cpu)      (false                 \
+                                )
+
 /* Whether the processor uses hardware interlocks to protect
    reads from the HI and LO registers, and thus does not
    require nops to be inserted.  */
@@ -295,10 +327,6 @@ enum mips_pic_level
   /* Do not generate PIC code.  */
   NO_PIC,
 
-  /* Generate PIC code as in Irix 4.  This is not implemented, and I'm
-     not sure what it is supposed to do.  */
-  IRIX4_PIC,
-
   /* Generate PIC code as in the SVR4 MIPS ABI.  */
   SVR4_PIC,
 
@@ -314,13 +342,13 @@ 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
+/* 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;
+static int mips_big_got = 0;
 
 /* 1 if trap instructions should used for overflow rather than break
    instructions.  */
-static int mips_trap;
+static int mips_trap = 0;
 
 /* 1 if double width floating point constants should not be constructed
    by assembling two single width halves into two single width floating
@@ -407,15 +435,24 @@ static offsetT mips_cprestore_offset = -1;
 
 /* Similiar for NewABI PIC code, where $gp is callee-saved.  NewABI has some
    more optimizations, it can use a register value instead of a memory-saved
-   offset and even an other than GP as global pointer.  */
+   offset and even an other register than $gp as global pointer.  */
 static offsetT mips_cpreturn_offset = -1;
 static int mips_cpreturn_register = -1;
 static int mips_gp_register = GP;
+static int mips_gprel_offset = 0;
+
+/* Whether mips_cprestore_offset has been set in the current function
+   (or whether it has already been warned about, if not).  */
+static int mips_cprestore_valid = 0;
 
 /* This is the register which holds the stack frame, as set by the
    .frame pseudo-op.  This is needed to implement .cprestore.  */
 static int mips_frame_reg = SP;
 
+/* Whether mips_frame_reg has been set in the current function
+   (or whether it has already been warned about, if not).  */
+static int mips_frame_reg_valid = 0;
+
 /* To output NOP instructions correctly, we need to keep information
    about the previous two instructions.  */
 
@@ -676,13 +713,14 @@ static void macro_build ();
 static void mips16_macro_build PARAMS ((char *, int *, expressionS *,
                                        const char *, const char *,
                                        va_list));
+static void macro_build_jalr PARAMS ((int, expressionS *));
 static void macro_build_lui PARAMS ((char *place, int *counter,
                                     expressionS * ep, int regnum));
 static void set_at PARAMS ((int *counter, int reg, int unsignedp));
 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 *, int, expressionS *, int, int *));
+static void load_address PARAMS ((int *, int, expressionS *, int *));
 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));
@@ -694,12 +732,14 @@ static void mips16_ip PARAMS ((char *str, struct mips_cl_insn * ip));
 static void mips16_immed PARAMS ((char *, unsigned int, int, offsetT, boolean,
                                  boolean, boolean, unsigned long *,
                                  boolean *, unsigned short *));
+static int my_getPercentOp PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallParser PARAMS ((char **, unsigned int *, int *));
 static int my_getSmallExpression PARAMS ((expressionS *, char *));
 static void my_getExpression PARAMS ((expressionS *, char *));
 #ifdef OBJ_ELF
 static int support_64bit_objects PARAMS((void));
 #endif
+static void mips_set_option_string PARAMS ((const char **, const char *));
 static symbolS *get_symbol PARAMS ((void));
 static void mips_align PARAMS ((int to, int fill, symbolS *label));
 static void s_align PARAMS ((int));
@@ -728,12 +768,14 @@ static void s_mips_frame PARAMS ((int));
 static void s_mips_mask PARAMS ((int));
 static void s_mips_stab PARAMS ((int));
 static void s_mips_weakext PARAMS ((int));
-static void s_file PARAMS ((int));
+static void s_mips_file PARAMS ((int));
+static void s_mips_loc PARAMS ((int));
 static int mips16_extended_frag PARAMS ((fragS *, asection *, long));
-static const char *mips_isa_to_str PARAMS ((int));
-static const char *mips_cpu_to_str PARAMS ((int));
 static int validate_mips_insn PARAMS ((const struct mips_opcode *));
-static void show PARAMS ((FILE *, char *, int *, int *));
+static void show PARAMS ((FILE *, const char *, int *, int *));
+#ifdef OBJ_ELF
+static int mips_need_elf_addend_fixup PARAMS ((fixS *));
+#endif
 
 /* Return values of my_getSmallExpression().  */
 
@@ -772,9 +814,14 @@ struct mips_cpu_info
   int cpu;                    /* CPU number (default CPU if ISA).  */
 };
 
-static const struct mips_cpu_info *mips_cpu_info_from_name PARAMS ((const char *));
+static void mips_set_architecture PARAMS ((const struct mips_cpu_info *));
+static void mips_set_tune PARAMS ((const struct mips_cpu_info *));
+static boolean mips_strict_matching_cpu_name_p PARAMS ((const char *,
+                                                       const char *));
+static boolean mips_matching_cpu_name_p PARAMS ((const char *, const char *));
+static const struct mips_cpu_info *mips_parse_cpu PARAMS ((const char *,
+                                                          const char *));
 static const struct mips_cpu_info *mips_cpu_info_from_isa PARAMS ((int));
-static const struct mips_cpu_info *mips_cpu_info_from_cpu PARAMS ((int));
 \f
 /* Pseudo-op table.
 
@@ -842,9 +889,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
 
-#ifdef MIPS_STABS_ELF
   { "extern", ecoff_directive_extern, 0},
-#endif
 
   { NULL, NULL, 0 },
 };
@@ -858,10 +903,10 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] =
   {"end", s_mips_end, 0},
   {"endb", s_ignore, 0},
   {"ent", s_mips_ent, 0},
-  {"file", s_file, 0},
+  {"file", s_mips_file, 0},
   {"fmask", s_mips_mask, 'F'},
   {"frame", s_mips_frame, 0},
-  {"loc", s_ignore, 0},
+  {"loc", s_mips_loc, 0},
   {"mask", s_mips_mask, 'R'},
   {"verstamp", s_ignore, 0},
   { NULL, NULL, 0 },
@@ -924,41 +969,10 @@ static boolean imm_unmatched_hi;
 
 static boolean mips16_small, mips16_ext;
 
-#ifdef MIPS_STABS_ELF
-/* The pdr segment for per procedure frame/regmask info */
+/* The pdr segment for per procedure frame/regmask info.  Not used for
+   ECOFF debugging.  */
 
 static segT pdr_seg;
-#endif
-
-static const char *
-mips_isa_to_str (isa)
-     int isa;
-{
-  const struct mips_cpu_info *ci;
-  static char s[20];
-
-  ci = mips_cpu_info_from_isa (isa);
-  if (ci != NULL)
-    return (ci->name);
-
-  sprintf (s, "ISA#%d", isa);
-  return s;
-}
-
-static const char *
-mips_cpu_to_str (cpu)
-     int cpu;
-{
-  const struct mips_cpu_info *ci;
-  static char s[16];
-
-  ci = mips_cpu_info_from_cpu (cpu);
-  if (ci != NULL)
-    return (ci->name);
-
-  sprintf (s, "CPU#%d", cpu);
-  return s;
-}
 
 /* The default target format to use.  */
 
@@ -975,17 +989,26 @@ mips_target_format ()
       return "pe-mips";
     case bfd_target_elf_flavour:
 #ifdef TE_TMIPS
-      /* This is traditional mips */
+      /* This is traditional mips */
       return (target_big_endian
-             ? (HAVE_64BIT_OBJECTS ? "elf64-tradbigmips"
-                : "elf32-tradbigmips")
-             : (HAVE_64BIT_OBJECTS ? "elf64-tradlittlemips"
-                : "elf32-tradlittlemips"));
+             ? (HAVE_64BIT_OBJECTS
+                ? "elf64-tradbigmips"
+                : (HAVE_NEWABI
+                   ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
+             : (HAVE_64BIT_OBJECTS
+                ? "elf64-tradlittlemips"
+                : (HAVE_NEWABI
+                   ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
 #else
       return (target_big_endian
-             ? (HAVE_64BIT_OBJECTS ? "elf64-bigmips" : "elf32-bigmips")
-             : (HAVE_64BIT_OBJECTS ? "elf64-littlemips"
-                : "elf32-littlemips"));
+             ? (HAVE_64BIT_OBJECTS
+                ? "elf64-bigmips"
+                : (HAVE_NEWABI
+                   ? "elf32-nbigmips" : "elf32-bigmips"))
+             : (HAVE_64BIT_OBJECTS
+                ? "elf64-littlemips"
+                : (HAVE_NEWABI
+                   ? "elf32-nlittlemips" : "elf32-littlemips")));
 #endif
     default:
       abort ();
@@ -1001,157 +1024,11 @@ md_begin ()
 {
   register const char *retval = NULL;
   int i = 0;
-  const char *cpu;
-  char *a = NULL;
   int broken = 0;
-  int mips_isa_from_cpu;
-  int target_cpu_had_mips16 = 0;
-  const struct mips_cpu_info *ci;
-
-  /* GP relative stuff not working for PE */
-  if (strncmp (TARGET_OS, "pe", 2) == 0
-      && g_switch_value != 0)
-    {
-      if (g_switch_seen)
-       as_bad (_("-G not supported in this configuration."));
-      g_switch_value = 0;
-    }
-
-  cpu = TARGET_CPU;
-  if (strcmp (cpu + (sizeof TARGET_CPU) - 3, "el") == 0)
-    {
-      a = xmalloc (sizeof TARGET_CPU);
-      strcpy (a, TARGET_CPU);
-      a[(sizeof TARGET_CPU) - 3] = '\0';
-      cpu = a;
-    }
-
-  if (strncmp (cpu, "mips16", sizeof "mips16" - 1) == 0)
-    {
-      target_cpu_had_mips16 = 1;
-      cpu += sizeof "mips16" - 1;
-    }
-
-  if (mips_opts.mips16 < 0)
-    mips_opts.mips16 = target_cpu_had_mips16;
-
-  /* Backward compatibility for historic -mcpu= option.  Check for
-     incompatible options, warn if -mcpu is used.  */
-  if (mips_cpu != CPU_UNKNOWN
-      && mips_arch != CPU_UNKNOWN
-      && mips_cpu != mips_arch)
-    {
-      as_fatal (_("The -mcpu option can't be used together with -march. "
-                 "Use -mtune instead of -mcpu."));
-    }
-
-  if (mips_cpu != CPU_UNKNOWN
-      && mips_tune != CPU_UNKNOWN
-      && mips_cpu != mips_tune)
-    {
-      as_fatal (_("The -mcpu option can't be used together with -mtune. "
-                 "Use -march instead of -mcpu."));
-    }
-
-  if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
-    {
-      ci = mips_cpu_info_from_cpu (mips_cpu);
-      assert (ci != NULL);
-      mips_arch = ci->cpu;
-      as_warn (_("The -mcpu option is deprecated.  Please use -march and "
-                "-mtune instead."));
-    }
-
-  /* At this point, mips_arch will either be CPU_UNKNOWN if no ARCH was
-     specified on the command line, or some other value if one was.
-     Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
-     the command line, or will be set otherwise if one was.  */
-  if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
-    {
-      /* We have to check if the isa is the default isa of arch.  Otherwise
-         we'll get invalid object file headers.  */
-      ci = mips_cpu_info_from_cpu (mips_arch);
-      assert (ci != NULL);
-      if (mips_opts.isa != ci->isa)
-       {
-         /* This really should be an error instead of a warning, but old
-            compilers only have -mcpu which sets both arch and tune.  For
-            now, we discard arch and preserve tune.  */
-         as_warn (_("The -march option is incompatible to -mipsN and "
-                    "therefore ignored."));
-         if (mips_tune == CPU_UNKNOWN)
-           mips_tune = mips_arch;
-         ci = mips_cpu_info_from_isa (mips_opts.isa);
-         assert (ci != NULL);
-         mips_arch = ci->cpu;
-       }
-    }
-  else if (mips_arch != CPU_UNKNOWN && mips_opts.isa == ISA_UNKNOWN)
-    {
-      /* We have ARCH, we need ISA.  */
-      ci = mips_cpu_info_from_cpu (mips_arch);
-      assert (ci != NULL);
-      mips_opts.isa = ci->isa;
-    }
-  else if (mips_arch == CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
-    {
-      /* We have ISA, we need default ARCH.  */
-      ci = mips_cpu_info_from_isa (mips_opts.isa);
-      assert (ci != NULL);
-      mips_arch = ci->cpu;
-    }
-  else
-    {
-      /* We need to set both ISA and ARCH from target cpu.  */
-      ci = mips_cpu_info_from_name (cpu);
-      if (ci == NULL)
-       ci = mips_cpu_info_from_cpu (CPU_R3000);
-      assert (ci != NULL);
-      mips_opts.isa = ci->isa;
-      mips_arch = ci->cpu;
-    }
-
-  if (mips_tune == CPU_UNKNOWN)
-    mips_tune = mips_arch;
-
-  ci = mips_cpu_info_from_cpu (mips_arch);
-  assert (ci != NULL);
-  mips_isa_from_cpu = ci->isa;
-
-  /* End of TARGET_CPU processing, get rid of malloced memory
-     if necessary.  */
-  cpu = NULL;
-  if (a != NULL)
-    {
-      free (a);
-      a = NULL;
-    }
-
-  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
-    as_bad (_("trap exception not supported at ISA 1"));
-
-  /* Set the EABI kind based on the ISA before the user gets
-     to change the ISA with directives.  This isn't really
-     the best, but then neither is basing the abi on the isa.  */
-  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && mips_opts.abi == EABI_ABI)
-    mips_eabi64 = 1;
-
-  /* If they asked for mips1 or mips2 and a cpu that is
-     mips3 or greater, then mark the object file 32BITMODE.  */
-  if (mips_isa_from_cpu != ISA_UNKNOWN
-      && ! ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && ISA_HAS_64BIT_REGS (mips_isa_from_cpu))
-    mips_32bitmode = 1;
 
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
-  file_mips_isa = mips_opts.isa;
-  file_mips_abi = mips_opts.abi;
-  mips_opts.gp32 = file_mips_gp32;
-  mips_opts.fp32 = file_mips_fp32;
-
   op_hash = hash_new ();
 
   for (i = 0; i < NUMOPCODES;)
@@ -1218,6 +1095,8 @@ md_begin ()
       symbol_table_insert (symbol_new (buf, reg_section, i,
                                       &zero_address_frag));
     }
+  symbol_table_insert (symbol_new ("$ra", reg_section, RA,
+                                  &zero_address_frag));
   symbol_table_insert (symbol_new ("$fp", reg_section, FP,
                                   &zero_address_frag));
   symbol_table_insert (symbol_new ("$sp", reg_section, SP,
@@ -1230,6 +1109,8 @@ md_begin ()
                                   &zero_address_frag));
   symbol_table_insert (symbol_new ("$kt1", reg_section, KT1,
                                   &zero_address_frag));
+  symbol_table_insert (symbol_new ("$zero", reg_section, ZERO,
+                                  &zero_address_frag));
   symbol_table_insert (symbol_new ("$pc", reg_section, -1,
                                   &zero_address_frag));
 
@@ -1277,12 +1158,12 @@ md_begin ()
        if (strcmp (TARGET_OS, "elf") != 0)
          flags |= SEC_ALLOC | SEC_LOAD;
 
-       if (! HAVE_NEWABI)
+       if (mips_abi != N64_ABI)
          {
            sec = subseg_new (".reginfo", (subsegT) 0);
 
-           (void) bfd_set_section_flags (stdoutput, sec, flags);
-           (void) bfd_set_section_alignment (stdoutput, sec, 2);
+           bfd_set_section_flags (stdoutput, sec, flags);
+           bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
 
 #ifdef OBJ_ELF
            mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
@@ -1293,8 +1174,8 @@ md_begin ()
            /* The 64-bit ABI uses a .MIPS.options section rather than
                .reginfo section.  */
            sec = subseg_new (".MIPS.options", (subsegT) 0);
-           (void) bfd_set_section_flags (stdoutput, sec, flags);
-           (void) bfd_set_section_alignment (stdoutput, sec, 3);
+           bfd_set_section_flags (stdoutput, sec, flags);
+           bfd_set_section_alignment (stdoutput, sec, 3);
 
 #ifdef OBJ_ELF
            /* Set up the option header.  */
@@ -1323,12 +1204,15 @@ md_begin ()
                                          SEC_HAS_CONTENTS | SEC_READONLY);
            (void) bfd_set_section_alignment (stdoutput, sec, 2);
          }
-
-#ifdef MIPS_STABS_ELF
-       pdr_seg = subseg_new (".pdr", (subsegT) 0);
-       (void) bfd_set_section_flags (stdoutput, pdr_seg,
-                            SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
-       (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+#ifdef OBJ_ELF
+       else if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+         {
+           pdr_seg = subseg_new (".pdr", (subsegT) 0);
+           (void) bfd_set_section_flags (stdoutput, pdr_seg,
+                                         SEC_READONLY | SEC_RELOC
+                                         | SEC_DEBUGGING);
+           (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+         }
 #endif
 
        subseg_set (seg, subseg);
@@ -1413,8 +1297,8 @@ insn_uses_reg (ip, reg, class)
       class = MIPS_GR_REG;
     }
 
-  /* Don't report on general register 0, since it never changes.  */
-  if (class == MIPS_GR_REG && reg == 0)
+  /* Don't report on general register ZERO, since it never changes.  */
+  if (class == MIPS_GR_REG && reg == ZERO)
     return 0;
 
   if (class == MIPS_FP_REG)
@@ -1554,8 +1438,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
   int nops = 0;
 
   /* Mark instruction labels in mips16 mode.  */
-  if (mips_opts.mips16)
-    mips16_mark_labels ();
+  mips16_mark_labels ();
 
   prev_pinfo = prev_insn.insn_mo->pinfo;
   pinfo = ip->insn_mo->pinfo;
@@ -1713,7 +1596,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                                     MIPS_GR_REG))
 
        {
-         nops += 1;
+         ++nops;
        }
 
       else if (prev_pinfo & INSN_READ_LO)
@@ -1739,7 +1622,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          else if (mips_opts.mips16
                   && (mips_optimize == 0
                       || (pinfo & MIPS16_INSN_BRANCH)))
-           nops += 1;
+           ++nops;
        }
       else if (prev_insn.insn_mo->pinfo & INSN_READ_HI)
        {
@@ -1761,7 +1644,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          else if (mips_opts.mips16
                   && (mips_optimize == 0
                       || (pinfo & MIPS16_INSN_BRANCH)))
-           nops += 1;
+           ++nops;
        }
 
       /* If the previous instruction was in a noreorder section, then
@@ -1848,7 +1731,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              val = (valueT) frag_now_fix ();
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               val += 1;
+               ++val;
              S_SET_VALUE (l->label, val);
            }
 
@@ -1935,7 +1818,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
     {
       if (address_expr->X_op == O_constant)
        {
-         unsigned long tmp;
+         valueT tmp;
 
          switch (*reloc_type)
            {
@@ -1971,6 +1854,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
+             if (address_expr->X_add_number & ~0xfffffff
+                 || address_expr->X_add_number > 0x7fffffc)
+               as_bad (_("jump address range overflow (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
              break;
 
@@ -1978,6 +1865,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
+             if (address_expr->X_add_number & ~0xfffffff
+                 || address_expr->X_add_number > 0x7fffffc)
+               as_bad (_("jump address range overflow (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |=
                (((address_expr->X_add_number & 0x7c0000) << 3)
                 | ((address_expr->X_add_number & 0xf800000) >> 7)
@@ -2011,21 +1902,21 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 4 octets for 64bit assembly.  */
              if (HAVE_64BIT_GPRS &&
                  (*reloc_type == BFD_RELOC_16
-                 || *reloc_type == BFD_RELOC_32
-                 || *reloc_type == BFD_RELOC_MIPS_JMP
-                 || *reloc_type == BFD_RELOC_HI16_S
-                 || *reloc_type == BFD_RELOC_LO16
-                 || *reloc_type == BFD_RELOC_GPREL16
-                 || *reloc_type == BFD_RELOC_MIPS_LITERAL
-                 || *reloc_type == BFD_RELOC_GPREL32
-                 || *reloc_type == BFD_RELOC_64
-                 || *reloc_type == BFD_RELOC_CTOR
-                 || *reloc_type == BFD_RELOC_MIPS_SUB
-                 || *reloc_type == BFD_RELOC_MIPS_HIGHEST
-                 || *reloc_type == BFD_RELOC_MIPS_HIGHER
-                 || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
-                 || *reloc_type == BFD_RELOC_MIPS_REL16
-                 || *reloc_type == BFD_RELOC_MIPS_RELGOT))
+                  || *reloc_type == BFD_RELOC_32
+                  || *reloc_type == BFD_RELOC_MIPS_JMP
+                  || *reloc_type == BFD_RELOC_HI16_S
+                  || *reloc_type == BFD_RELOC_LO16
+                  || *reloc_type == BFD_RELOC_GPREL16
+                  || *reloc_type == BFD_RELOC_MIPS_LITERAL
+                  || *reloc_type == BFD_RELOC_GPREL32
+                  || *reloc_type == BFD_RELOC_64
+                  || *reloc_type == BFD_RELOC_CTOR
+                  || *reloc_type == BFD_RELOC_MIPS_SUB
+                  || *reloc_type == BFD_RELOC_MIPS_HIGHEST
+                  || *reloc_type == BFD_RELOC_MIPS_HIGHER
+                  || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
+                  || *reloc_type == BFD_RELOC_MIPS_REL16
+                  || *reloc_type == BFD_RELOC_MIPS_RELGOT))
                fixp[0]->fx_no_overflow = 1;
 
              if (unmatched_hi)
@@ -2072,7 +1963,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                       || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
                       || *reloc_type == BFD_RELOC_MIPS_REL16
                       || *reloc_type == BFD_RELOC_MIPS_RELGOT))
-                    fixp[1]->fx_no_overflow = 1;
+                   fixp[1]->fx_no_overflow = 1;
 
                  if (reloc_type[2] != BFD_RELOC_UNUSED)
                    {
@@ -2104,7 +1995,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                           || *reloc_type == BFD_RELOC_MIPS_SCN_DISP
                           || *reloc_type == BFD_RELOC_MIPS_REL16
                           || *reloc_type == BFD_RELOC_MIPS_RELGOT))
-                      fixp[2]->fx_no_overflow = 1;
+                       fixp[2]->fx_no_overflow = 1;
                    }
                }
            }
@@ -2112,11 +2003,19 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
     }
 
   if (! mips_opts.mips16)
-    md_number_to_chars (f, ip->insn_opcode, 4);
+    {
+      md_number_to_chars (f, ip->insn_opcode, 4);
+#ifdef OBJ_ELF
+      dwarf2_emit_insn (4);
+#endif
+    }
   else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
     {
       md_number_to_chars (f, ip->insn_opcode >> 16, 2);
       md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
+#ifdef OBJ_ELF
+      dwarf2_emit_insn (4);
+#endif
     }
   else
     {
@@ -2126,6 +2025,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          f += 2;
        }
       md_number_to_chars (f, ip->insn_opcode, 2);
+#ifdef OBJ_ELF
+      dwarf2_emit_insn (ip->use_extend ? 4 : 2);
+#endif
     }
 
   /* Update the register mask information.  */
@@ -2138,7 +2040,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       if (pinfo & INSN_READ_GPR_S)
        mips_gprmask |= 1 << ((ip->insn_opcode >> OP_SH_RS) & OP_MASK_RS);
       if (pinfo & INSN_WRITE_GPR_31)
-       mips_gprmask |= 1 << 31;
+       mips_gprmask |= 1 << RA;
       if (pinfo & INSN_WRITE_FPR_D)
        mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FD) & OP_MASK_FD);
       if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
@@ -2331,7 +2233,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                      || ((pinfo & INSN_WRITE_GPR_31)
                          && (((prev_insn.insn_opcode >> OP_SH_RT)
                               & OP_MASK_RT)
-                             == 31))))
+                             == RA))))
              || (! mips_opts.mips16
                  && (prev_pinfo & INSN_WRITE_GPR_D)
                  && (((pinfo & INSN_WRITE_GPR_D)
@@ -2340,7 +2242,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                      || ((pinfo & INSN_WRITE_GPR_31)
                          && (((prev_insn.insn_opcode >> OP_SH_RD)
                               & OP_MASK_RD)
-                             == 31))))
+                             == RA))))
              || (mips_opts.mips16
                  && (pinfo & MIPS16_INSN_WRITE_31)
                  && ((prev_pinfo & MIPS16_INSN_WRITE_31)
@@ -2358,7 +2260,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                                    MIPS_GR_REG))
              || (! mips_opts.mips16
                  && (pinfo & INSN_WRITE_GPR_31)
-                 && insn_uses_reg (&prev_insn, 31, MIPS_GR_REG))
+                 && insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
              || (mips_opts.mips16
                  && (pinfo & MIPS16_INSN_WRITE_31)
                  && insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
@@ -2716,14 +2618,14 @@ mips_emit_delays (insns)
              val = (valueT) frag_now_fix ();
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               val += 1;
+               ++val;
              S_SET_VALUE (l->label, val);
            }
        }
     }
 
   /* Mark instruction labels in mips16 mode.  */
-  if (mips_opts.mips16 && insns)
+  if (insns)
     mips16_mark_labels ();
 
   mips_no_prev_insn (insns);
@@ -2771,8 +2673,20 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   if (mips_opts.warn_about_macros && place == NULL && *counter == 1)
     as_warn (_("Macro instruction expanded into multiple instructions"));
 
+  /*
+   * If the macro is about to expand into a second instruction,
+   * and it is in a delay slot, print a warning.
+   */
+  if (place == NULL
+      && *counter == 1
+      && mips_opts.noreorder
+      && (prev_prev_insn.insn_mo->pinfo
+         & (INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_DELAY
+            | INSN_COND_BRANCH_LIKELY)) != 0)
+    as_warn (_("Macro instruction expanded into multiple instructions in a branch delay slot"));
+
   if (place == NULL)
-    *counter += 1;             /* bump instruction counter */
+    ++*counter;                /* bump instruction counter */
 
   if (mips_opts.mips16)
     {
@@ -2791,9 +2705,14 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   /* Search until we get a match for NAME.  */
   while (1)
     {
+      /* It is assumed here that macros will never generate 
+         MDMX or MIPS-3D instructions.  */
       if (strcmp (fmt, insn.insn_mo->args) == 0
          && insn.insn_mo->pinfo != INSN_MACRO
-         && OPCODE_IS_MEMBER (insn.insn_mo, mips_opts.isa, mips_arch)
+         && OPCODE_IS_MEMBER (insn.insn_mo,
+                              (mips_opts.isa
+                               | (mips_opts.mips16 ? INSN_MIPS16 : 0)),
+                              mips_arch)
          && (mips_arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
        break;
 
@@ -2883,13 +2802,16 @@ macro_build (place, counter, ep, name, fmt, va_alist)
        case 'j':
        case 'o':
          *r = (bfd_reloc_code_real_type) va_arg (args, int);
-         assert (*r == BFD_RELOC_MIPS_GPREL
+         assert (*r == BFD_RELOC_GPREL16
                  || *r == BFD_RELOC_MIPS_LITERAL
                  || *r == BFD_RELOC_MIPS_HIGHER
                  || *r == BFD_RELOC_HI16_S
                  || *r == BFD_RELOC_LO16
                  || *r == BFD_RELOC_MIPS_GOT16
                  || *r == BFD_RELOC_MIPS_CALL16
+                 || *r == BFD_RELOC_MIPS_GOT_DISP
+                 || *r == BFD_RELOC_MIPS_GOT_PAGE
+                 || *r == BFD_RELOC_MIPS_GOT_OFST
                  || *r == BFD_RELOC_MIPS_GOT_LO16
                  || *r == BFD_RELOC_MIPS_CALL_LO16
                  || (ep->X_op == O_subtract
@@ -3053,7 +2975,7 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
            assert (ep != NULL);
 
            if (ep->X_op != O_constant)
-             *r = BFD_RELOC_UNUSED + c;
+             *r = (int) BFD_RELOC_UNUSED + c;
            else
              {
                mips16_immed (NULL, 0, c, ep->X_add_number, false, false,
@@ -3078,6 +3000,29 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
   append_insn (place, &insn, ep, r, false);
 }
 
+/*
+ * Generate a "jalr" instruction with a relocation hint to the called
+ * function.  This occurs in NewABI PIC code.
+ */
+static void
+macro_build_jalr (icnt, ep)
+     int icnt;
+     expressionS *ep;
+{
+  char *f;
+  
+  if (HAVE_NEWABI)
+    {
+      frag_grow (4);
+      f = frag_more (0);
+    }
+  macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
+              RA, PIC_CALL_REG);
+  if (HAVE_NEWABI)
+    fix_new_exp (frag_now, f - frag_now->fr_literal,
+                0, ep, false, BFD_RELOC_MIPS_JALR);
+}
+
 /*
  * Generate a "lui" instruction.
  */
@@ -3092,8 +3037,8 @@ macro_build_lui (place, counter, ep, regnum)
   struct mips_cl_insn insn;
   bfd_reloc_code_real_type r[3]
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
-  CONST char *name = "lui";
-  CONST char *fmt = "t,u";
+  const char *name = "lui";
+  const char *fmt = "t,u";
 
   assert (! mips_opts.mips16);
 
@@ -3130,7 +3075,7 @@ macro_build_lui (place, counter, ep, regnum)
     as_warn (_("Macro instruction expanded into multiple instructions"));
 
   if (place == NULL)
-    *counter += 1;             /* bump instruction counter */
+    ++*counter;                /* bump instruction counter */
 
   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
   assert (insn.insn_mo);
@@ -3165,7 +3110,7 @@ set_at (counter, reg, unsignedp)
                 "t,r,j", AT, reg, (int) BFD_RELOC_LO16);
   else
     {
-      load_register (counter, AT, &imm_expr, 0);
+      load_register (counter, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, counter, (expressionS *) NULL,
                   unsignedp ? "sltu" : "slt",
                   "d,v,t", AT, reg, AT);
@@ -3261,6 +3206,11 @@ check_absolute_expr (ip, ex)
            ? 1                          \
            : 0)
 
+/* Is the given value a sign-extended 32-bit value?  */
+#define IS_SEXT_32BIT_NUM(x)                                           \
+  (((x) &~ (offsetT) 0x7fffffff) == 0                                  \
+   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
+
 /*                     load_register()
  *  This routine generates the least number of instructions neccessary to load
  *  an absolute expression value into a register.
@@ -3300,9 +3250,7 @@ load_register (counter, reg, ep, dbl)
                       (int) BFD_RELOC_LO16);
          return;
        }
-      else if ((((ep->X_add_number &~ (offsetT) 0x7fffffff) == 0
-                || ((ep->X_add_number &~ (offsetT) 0x7fffffff)
-                    == ~ (offsetT) 0x7fffffff))
+      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)
                && (! dbl
                    || ! ep->X_unsigned
                    || sizeof (ep->X_add_number) > 4
@@ -3328,7 +3276,8 @@ load_register (counter, reg, ep, dbl)
 
   if (HAVE_32BIT_GPRS)
     {
-      as_bad (_("Number larger than 32 bits"));
+      as_bad (_("Number (0x%lx) larger than 32 bits"),
+             (unsigned long) ep->X_add_number);
       macro_build ((char *) NULL, counter, ep, "addiu", "t,r,j", reg, 0,
                   (int) BFD_RELOC_LO16);
       return;
@@ -3363,7 +3312,7 @@ load_register (counter, reg, ep, dbl)
       int shift, bit;
       unsigned long hi, lo;
 
-      if (hi32.X_add_number == 0xffffffff)
+      if (hi32.X_add_number == (offsetT) 0xffffffff)
        {
          if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
            {
@@ -3420,7 +3369,7 @@ load_register (counter, reg, ep, dbl)
                           (shift >= 32) ? shift - 32 : shift);
              return;
            }
-         shift++;
+         ++shift;
        }
       while (shift <= (64 - 16));
 
@@ -3502,27 +3451,27 @@ load_register (counter, reg, ep, dbl)
     {
       expressionS mid16;
 
-      if ((freg == 0) && (lo32.X_add_number == 0xffffffff))
+      if ((freg == 0) && (lo32.X_add_number == (offsetT) 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);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL,
+                      "dsrl32", "d,w,<", reg, reg, 0);
          return;
        }
 
       if (freg != 0)
        {
-         macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
-                      freg, 16);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL, "dsll",
+                      "d,w,<", reg, freg, 16);
          freg = reg;
        }
       mid16 = lo32;
       mid16.X_add_number >>= 16;
       macro_build ((char *) NULL, counter, &mid16, "ori", "t,r,i", reg,
                   freg, (int) BFD_RELOC_LO16);
-      macro_build ((char *) NULL, counter, NULL, "dsll", "d,w,<", reg,
-                  reg, 16);
+      macro_build ((char *) NULL, counter, (expressionS *) NULL, "dsll",
+                  "d,w,<", reg, reg, 16);
       freg = reg;
     }
   if ((lo32.X_add_number & 0xffff) != 0)
@@ -3533,14 +3482,13 @@ load_register (counter, reg, ep, dbl)
 /* Load an address into a register.  */
 
 static void
-load_address (counter, reg, ep, dbl, used_at)
+load_address (counter, reg, ep, used_at)
      int *counter;
      int reg;
      expressionS *ep;
-     int dbl;
      int *used_at;
 {
-  char *p;
+  char *p = NULL;
 
   if (ep->X_op != O_constant
       && ep->X_op != O_symbol)
@@ -3551,14 +3499,14 @@ load_address (counter, reg, ep, dbl, used_at)
 
   if (ep->X_op == O_constant)
     {
-      load_register (counter, reg, ep, dbl);
+      load_register (counter, reg, ep, HAVE_64BIT_ADDRESSES);
       return;
     }
 
   if (mips_pic == NO_PIC)
     {
       /* If this is a reference to a GP relative symbol, we want
-          addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
+          addiu        $reg,$gp,<sym>          (BFD_RELOC_GPREL16)
         Otherwise we want
           lui          $reg,<sym>              (BFD_RELOC_HI16_S)
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
@@ -3570,7 +3518,7 @@ load_address (counter, reg, ep, dbl, used_at)
           daddiu       $reg,<sym>              (BFD_RELOC_MIPS_HIGHER)
           daddiu       $at,<sym>               (BFD_RELOC_LO16)
           dsll32       $reg,0
-          dadd         $reg,$reg,$at
+          daddu        $reg,$reg,$at
 
         If $at is already in use, we use an path which is suboptimal
         on superscalar processors.
@@ -3583,12 +3531,10 @@ load_address (counter, reg, ep, dbl, used_at)
        */
       if (HAVE_64BIT_ADDRESSES)
        {
-         p = NULL;
-
          /* We don't do GP optimization for now because RELAX_ENCODE can't
             hold the data for such large chunks.  */
 
-         if (*used_at == 0)
+         if (*used_at == 0 && ! mips_opts.noat)
            {
              macro_build (p, counter, ep, "lui", "t,u",
                           reg, (int) BFD_RELOC_MIPS_HIGHEST);
@@ -3600,7 +3546,7 @@ load_address (counter, reg, ep, dbl, used_at)
                           AT, AT, (int) BFD_RELOC_LO16);
              macro_build (p, counter, (expressionS *) NULL, "dsll32",
                           "d,w,<", reg, reg, 0);
-             macro_build (p, counter, (expressionS *) NULL, "dadd",
+             macro_build (p, counter, (expressionS *) NULL, "daddu",
                           "d,v,t", reg, reg, AT);
              *used_at = 1;
            }
@@ -3622,18 +3568,17 @@ load_address (counter, reg, ep, dbl, used_at)
        }
       else
        {
-         p = NULL;
          if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
              && ! nopic_need_relax (ep->X_add_symbol, 1))
            {
              frag_grow (20);
              macro_build ((char *) NULL, counter, ep,
-                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                          "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j",
+                          reg, mips_gp_register, (int) BFD_RELOC_GPREL16);
              p = frag_var (rs_machine_dependent, 8, 0,
                            RELAX_ENCODE (4, 8, 0, 4, 0,
                                          mips_opts.warn_about_macros),
-                           ep->X_add_symbol, (offsetT) 0, (char *) NULL);
+                           ep->X_add_symbol, 0, NULL);
            }
          macro_build_lui (p, counter, ep, reg);
          if (p != NULL)
@@ -3658,8 +3603,8 @@ load_address (counter, reg, ep, dbl, used_at)
       ep->X_add_number = 0;
       frag_grow (20);
       macro_build ((char *) NULL, counter, ep,
-                  HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                  "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                  HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
+                  reg, (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
       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),
@@ -3691,42 +3636,60 @@ load_address (counter, reg, ep, dbl, used_at)
           lw           $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT16)
           nop
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
+        If we have NewABI, we want
+          lw           $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT_PAGE)
+          addiu        $reg,$reg,<sym>         (BFD_RELOC_MIPS_GOT_OFST)
         If there is a constant, it must be added in after.  */
       ex.X_add_number = ep->X_add_number;
       ep->X_add_number = 0;
-      if (reg_needs_delay (GP))
-       off = 4;
+      if (HAVE_NEWABI)
+       {
+         macro_build ((char *) NULL, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg,
+                      (int) BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j",
+                      reg, reg, (int) BFD_RELOC_MIPS_GOT_OFST);
+       }
       else
-       off = 0;
-      frag_grow (32);
-      macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
-                  (int) BFD_RELOC_MIPS_GOT_HI16);
-      macro_build ((char *) NULL, counter, (expressionS *) NULL,
-                  HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                  "d,v,t", reg, reg, GP);
-      macro_build ((char *) NULL, counter, ep,
-                  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,
-                                 mips_opts.warn_about_macros),
-                   ep->X_add_symbol, (offsetT) 0, (char *) NULL);
-      if (off > 0)
        {
-         /* We need a nop before loading from $gp.  This special
-             check is required because the lui which starts the main
-             instruction stream does not refer to $gp, and so will not
-             insert the nop which may be required.  */
+         if (reg_needs_delay (mips_gp_register))
+           off = 4;
+         else
+           off = 0;
+         frag_grow (32);
+         macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
+                      (int) BFD_RELOC_MIPS_GOT_HI16);
+         macro_build ((char *) NULL, counter, (expressionS *) NULL,
+                      HAVE_32BIT_ADDRESSES ? "addu" : "daddu", "d,v,t", reg,
+                      reg, mips_gp_register);
+         macro_build ((char *) NULL, counter, ep,
+                      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,
+                                     mips_opts.warn_about_macros),
+                       ep->X_add_symbol, 0, NULL);
+         if (off > 0)
+           {
+             /* We need a nop before loading from $gp.  This special
+                check is required because the lui which starts the main
+                instruction stream does not refer to $gp, and so will not
+                insert the nop which may be required.  */
+             macro_build (p, counter, (expressionS *) NULL, "nop", "");
+               p += 4;
+           }
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg,
+                      (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
+         p += 4;
          macro_build (p, counter, (expressionS *) NULL, "nop", "");
          p += 4;
+         macro_build (p, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                      "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
-      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, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                  "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
+
       if (ex.X_add_number != 0)
        {
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
@@ -3740,11 +3703,11 @@ load_address (counter, reg, ep, dbl, used_at)
   else if (mips_pic == EMBEDDED_PIC)
     {
       /* We always do
-          addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
-        */
+          addiu        $reg,$gp,<sym>          (BFD_RELOC_GPREL16)
+       */
       macro_build ((char *) NULL, counter, ep,
                   HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                  "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                  "t,r,j", reg, mips_gp_register, (int) BFD_RELOC_GPREL16);
     }
   else
     abort ();
@@ -3802,7 +3765,6 @@ macro (ip)
   offsetT maxnum;
   int off;
   bfd_reloc_code_real_type r;
-  char *p;
   int hold_mips_optimize;
 
   assert (! mips_opts.mips16);
@@ -3933,7 +3895,7 @@ macro (ip)
                       0);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "s,t,p", sreg, AT);
       break;
 
@@ -3996,7 +3958,7 @@ macro (ip)
        }
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
-      imm_expr.X_add_number++;
+      ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BGE_I:
     case M_BGEL_I:
@@ -4061,11 +4023,11 @@ macro (ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == 0xffffffff))
+             && imm_expr.X_add_number == (offsetT) 0xffffffff))
        goto do_false;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
-      imm_expr.X_add_number++;
+      ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BGEU_I:
     case M_BGEUL_I:
@@ -4160,7 +4122,7 @@ macro (ip)
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
-      imm_expr.X_add_number++;
+      ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BLT_I:
     case M_BLTL_I:
@@ -4206,11 +4168,11 @@ macro (ip)
       if (sreg == 0
          || (HAVE_32BIT_GPRS
              && imm_expr.X_op == O_constant
-             && imm_expr.X_add_number == 0xffffffff))
+             && imm_expr.X_add_number == (offsetT) 0xffffffff))
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
-      imm_expr.X_add_number++;
+      ++imm_expr.X_add_number;
       /* FALLTHROUGH */
     case M_BLTU_I:
     case M_BLTUL_I:
@@ -4284,7 +4246,7 @@ macro (ip)
          as_warn (_("Divide by zero."));
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
-                        "s,t", 0, 0);
+                        "s,t,q", 0, 0, 7);
          else
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
                         "c", 7);
@@ -4297,7 +4259,7 @@ macro (ip)
       if (mips_trap)
        {
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
-                      "s,t", treg, 0);
+                      "s,t,q", treg, 0, 7);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
@@ -4333,7 +4295,7 @@ macro (ip)
       if (mips_trap)
        {
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
-                      "s,t", sreg, AT);
+                      "s,t,q", sreg, AT, 6);
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
@@ -4396,7 +4358,7 @@ macro (ip)
          as_warn (_("Divide by zero."));
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
-                        "s,t", 0, 0);
+                        "s,t,q", 0, 0, 7);
          else
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
                         "c", 7);
@@ -4452,7 +4414,7 @@ macro (ip)
       if (mips_trap)
        {
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "teq",
-                      "s,t", treg, 0);
+                      "s,t,q", treg, 0, 7);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "z,s,t",
                       sreg, treg);
          /* We want to close the noreorder block as soon as possible, so
@@ -4481,6 +4443,22 @@ macro (ip)
       /* Load the address of a symbol into a register.  If breg is not
         zero, we then add a base register to it.  */
 
+      if (dbl && HAVE_32BIT_GPRS)
+       as_warn (_("dla used to load 32-bit register"));
+
+      if (! dbl && HAVE_64BIT_OBJECTS)
+       as_warn (_("la used to load 64-bit address"));
+
+      if (offset_expr.X_op == O_constant
+         && offset_expr.X_add_number >= -0x8000
+         && offset_expr.X_add_number < 0x8000)
+       {
+         macro_build ((char *) NULL, &icnt, &offset_expr,
+                      (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
+                      "t,r,j", treg, sreg, (int) BFD_RELOC_LO16);
+         return;
+       }
+
       if (treg == breg)
        {
          tempreg = AT;
@@ -4525,11 +4503,11 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                           tempreg, (int) BFD_RELOC_PCREL_HI16_S);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                          (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu",
                           "d,v,t", tempreg, tempreg, breg);
            }
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                      (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu",
                       "t,r,j", treg, tempreg, (int) BFD_RELOC_PCREL_LO16);
          if (! used_at)
            return;
@@ -4544,11 +4522,14 @@ macro (ip)
        }
 
       if (offset_expr.X_op == O_constant)
-       load_register (&icnt, tempreg, &offset_expr, dbl);
+       load_register (&icnt, tempreg, &offset_expr,
+                      ((mips_pic == EMBEDDED_PIC || mips_pic == NO_PIC)
+                       ? (dbl || HAVE_64BIT_ADDRESSES)
+                       : HAVE_64BIT_ADDRESSES));
       else if (mips_pic == NO_PIC)
        {
          /* If this is a reference to a GP relative symbol, we want
-              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
+              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_GPREL16)
             Otherwise we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
@@ -4561,7 +4542,7 @@ macro (ip)
              daddiu    $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHER)
              daddiu    $at,<sym>               (BFD_RELOC_LO16)
              dsll32    $tempreg,0
-             dadd      $tempreg,$tempreg,$at
+             daddu     $tempreg,$tempreg,$at
 
            If $at is already in use, we use an path which is suboptimal
            on superscalar processors.
@@ -4572,66 +4553,64 @@ macro (ip)
              dsll      $tempreg,16
              daddiu    $tempreg,<sym>          (BFD_RELOC_LO16)
          */
-         p = NULL;
+         char *p = NULL;
          if (HAVE_64BIT_ADDRESSES)
            {
              /* We don't do GP optimization for now because RELAX_ENCODE can't
                 hold the data for such large chunks.  */
 
-           if (used_at == 0)
-             {
-               macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                            tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
-               macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                            AT, (int) BFD_RELOC_HI16_S);
-               macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                            tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
-               macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                            AT, AT, (int) BFD_RELOC_LO16);
-               macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
-                            "d,w,<", tempreg, tempreg, 0);
-               macro_build (p, &icnt, (expressionS *) NULL, "dadd", "d,v,t",
-                            tempreg, tempreg, AT);
-               used_at = 1;
-             }
-           else
-             {
-               macro_build (p, &icnt, &offset_expr, "lui", "t,u",
-                            tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
-               macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                            tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
-               macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
-                            tempreg, tempreg, 16);
-               macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                            tempreg, tempreg, (int) BFD_RELOC_HI16_S);
-               macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
-                            tempreg, tempreg, 16);
-               macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
-                            tempreg, tempreg, (int) BFD_RELOC_LO16);
-             }
-         }
-       else
-         {
-           if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
-               && ! nopic_need_relax (offset_expr.X_add_symbol, 1))
-             {
-               frag_grow (20);
-               macro_build ((char *) NULL, &icnt, &offset_expr,
-                            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,
-                                           mips_opts.warn_about_macros),
-                             offset_expr.X_add_symbol, (offsetT) 0,
-                             (char *) NULL);
-             }
-           macro_build_lui (p, &icnt, &offset_expr, tempreg);
-           if (p != NULL)
-             p += 4;
-           macro_build (p, &icnt, &offset_expr,
-                        HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                        "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
-         }
+             if (used_at == 0 && ! mips_opts.noat)
+               {
+                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                              tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
+                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                              AT, (int) BFD_RELOC_HI16_S);
+                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                              tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
+                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                              AT, AT, (int) BFD_RELOC_LO16);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
+                              "d,w,<", tempreg, tempreg, 0);
+                 macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+                              "d,v,t", tempreg, tempreg, AT);
+                 used_at = 1;
+               }
+             else
+               {
+                 macro_build (p, &icnt, &offset_expr, "lui", "t,u",
+                              tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
+                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                              tempreg, tempreg, (int) BFD_RELOC_MIPS_HIGHER);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
+                              tempreg, tempreg, 16);
+                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                              tempreg, tempreg, (int) BFD_RELOC_HI16_S);
+                 macro_build (p, &icnt, (expressionS *) NULL, "dsll", "d,w,<",
+                              tempreg, tempreg, 16);
+                 macro_build (p, &icnt, &offset_expr, "daddiu", "t,r,j",
+                              tempreg, tempreg, (int) BFD_RELOC_LO16);
+               }
+           }
+         else
+           {
+             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
+                 && ! nopic_need_relax (offset_expr.X_add_symbol, 1))
+               {
+                 frag_grow (20);
+                 macro_build ((char *) NULL, &icnt, &offset_expr, "addiu",
+                              "t,r,j", tempreg, mips_gp_register,
+                              (int) BFD_RELOC_GPREL16);
+                 p = frag_var (rs_machine_dependent, 8, 0,
+                               RELAX_ENCODE (4, 8, 0, 4, 0,
+                                             mips_opts.warn_about_macros),
+                               offset_expr.X_add_symbol, 0, NULL);
+               }
+             macro_build_lui (p, &icnt, &offset_expr, tempreg);
+             if (p != NULL)
+               p += 4;
+             macro_build (p, &icnt, &offset_expr, "addiu",
+                          "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
+           }
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
@@ -4670,11 +4649,13 @@ macro (ip)
          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, lw_reloc_type, GP);
+         macro_build ((char *) NULL, &icnt, &offset_expr,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                      "t,o(b)", tempreg, lw_reloc_type, mips_gp_register);
          if (expr1.X_add_number == 0)
            {
              int off;
+             char *p;
 
              if (breg == 0)
                off = 0;
@@ -4764,6 +4745,7 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          int gpdel;
+         char *p;
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
 
@@ -4806,11 +4788,36 @@ macro (ip)
               lui      $at,<hiconstant>
               addiu    $at,$at,<loconstant>    (BFD_RELOC_LO16)
               addu     $tempreg,$tempreg,$at
-            */
+
+            For NewABI, we want for data addresses
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_DISP)
+            If tempreg is PIC_CALL_REG pointing to a external symbol, we want
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_CALL16)
+          */
+         if (HAVE_NEWABI)
+           {
+             int reloc_type = (tempreg == PIC_CALL_REG
+                               ? BFD_RELOC_MIPS_CALL16
+                               : BFD_RELOC_MIPS_GOT_DISP);
+
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                          "t,o(b)", tempreg, reloc_type, mips_gp_register);
+
+             if (breg != 0)
+               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                            HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                            "d,v,t", treg, tempreg, breg);
+
+             if (! used_at)
+               return;
+
+             break;
+           }
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          frag_grow (52);
-         if (reg_needs_delay (GP))
+         if (reg_needs_delay (mips_gp_register))
            gpdel = 4;
          else
            gpdel = 0;
@@ -4823,9 +4830,9 @@ macro (ip)
                       tempreg, lui_reloc_type);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                      "d,v,t", tempreg, tempreg, GP);
+                      "d,v,t", tempreg, tempreg, mips_gp_register);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      dbl ? "ld" : "lw",
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, lw_reloc_type, tempreg);
          if (expr1.X_add_number == 0)
            {
@@ -4928,8 +4935,9 @@ macro (ip)
              p += 4;
            }
          macro_build (p, &icnt, &offset_expr,
-                      dbl ? "ld" : "lw",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16,
+                      mips_gp_register);
          p += 4;
          if (expr1.X_add_number >= -0x8000
              && expr1.X_add_number < 0x8000)
@@ -4979,19 +4987,27 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* We use
-              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
+              addiu    $tempreg,$gp,<sym>      (BFD_RELOC_GPREL16)
             */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                      "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j",
+                      tempreg, mips_gp_register, (int) BFD_RELOC_GPREL16);
        }
       else
        abort ();
 
       if (breg != 0)
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                    "d,v,t", treg, tempreg, breg);
+       {
+         char *s;
+
+         if (mips_pic == EMBEDDED_PIC || mips_pic == NO_PIC)
+           s = (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu";
+         else
+           s = HAVE_64BIT_ADDRESSES ? "daddu" : "addu";
+
+         macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s,
+                      "d,v,t", treg, tempreg, breg);
+       }
 
       if (! used_at)
        return;
@@ -5032,10 +5048,23 @@ macro (ip)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
+                 if (! mips_frame_reg_valid)
+                   {
+                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_frame_reg_valid = 1;
+                   }
+                 if (! mips_cprestore_valid)
+                   {
+                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_cprestore_valid = 1;
+                   }
                  expr1.X_add_number = mips_cprestore_offset;
                  macro_build ((char *) NULL, &icnt, &expr1,
                               HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
-                              GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+                              mips_gp_register, (int) BFD_RELOC_LO16,
+                              mips_frame_reg);
                }
            }
        }
@@ -5049,11 +5078,13 @@ macro (ip)
        macro_build ((char *) NULL, &icnt, &offset_expr, "jal", "a");
       else if (mips_pic == SVR4_PIC)
        {
+         char *p;
+
          /* If this is a reference to an external symbol, and we are
             using a small GOT, we want
               lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
               nop
-              jalr     $25
+              jalr     $ra,$25
               nop
               lw       $gp,cprestore($sp)
             The cprestore value is set using the .cprestore
@@ -5062,84 +5093,111 @@ macro (ip)
               addu     $25,$25,$gp
               lw       $25,<sym>($25)          (BFD_RELOC_MIPS_CALL_LO16)
               nop
-              jalr     $25
+              jalr     $ra,$25
               nop
               lw       $gp,cprestore($sp)
             If the symbol is not external, we want
               lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
               nop
               addiu    $25,$25,<sym>           (BFD_RELOC_LO16)
-              jalr     $25
+              jalr     $ra,$25
               nop
-              lw $gp,cprestore($sp) */
-         frag_grow (40);
-         if (! mips_big_got)
+              lw $gp,cprestore($sp)
+            For NewABI, we want
+              lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_GOT_DISP)
+              jalr     $ra,$25                 (BFD_RELOC_MIPS_JALR)
+          */
+         if (HAVE_NEWABI)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr,
                           HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                           "t,o(b)", PIC_CALL_REG,
-                          (int) BFD_RELOC_MIPS_CALL16, GP);
-             macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          "nop", "");
-             p = frag_var (rs_machine_dependent, 4, 0,
-                           RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                           offset_expr.X_add_symbol, 0, NULL);
+                          (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+             macro_build_jalr (icnt, &offset_expr);
            }
          else
            {
-             int gpdel;
-
-             if (reg_needs_delay (GP))
-               gpdel = 4;
+             frag_grow (40);
+             if (! mips_big_got)
+               {
+                 macro_build ((char *) NULL, &icnt, &offset_expr,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                              "t,o(b)", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_CALL16, mips_gp_register);
+                 macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                              "nop", "");
+                 p = frag_var (rs_machine_dependent, 4, 0,
+                               RELAX_ENCODE (0, 4, -8, 0, 0, 0),
+                               offset_expr.X_add_symbol, 0, NULL);
+               }
              else
-               gpdel = 0;
-             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,
-                          HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                          "d,v,t", PIC_CALL_REG, PIC_CALL_REG, GP);
-             macro_build ((char *) NULL, &icnt, &offset_expr,
-                          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,
-                          "nop", "");
-             p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
-                           RELAX_ENCODE (16, 12 + gpdel, gpdel, 8 + gpdel,
-                                         0, 0),
-                           offset_expr.X_add_symbol, 0, NULL);
-             if (gpdel > 0)
                {
+                 int gpdel;
+
+                 if (reg_needs_delay (mips_gp_register))
+                   gpdel = 4;
+                 else
+                   gpdel = 0;
+                 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,
+                              HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                              "d,v,t", PIC_CALL_REG, PIC_CALL_REG,
+                              mips_gp_register);
+                 macro_build ((char *) NULL, &icnt, &offset_expr,
+                              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,
+                              "nop", "");
+                 p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
+                               RELAX_ENCODE (16, 12 + gpdel, gpdel,
+                                             8 + gpdel, 0, 0),
+                               offset_expr.X_add_symbol, 0, NULL);
+                 if (gpdel > 0)
+                   {
+                     macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
+                     p += 4;
+                   }
+                 macro_build (p, &icnt, &offset_expr,
+                              HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                              "t,o(b)", PIC_CALL_REG,
+                              (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
+                 p += 4;
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
                  p += 4;
                }
              macro_build (p, &icnt, &offset_expr,
-                          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,
-                      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,
-                      "jalr", "s", PIC_CALL_REG);
-         if (! HAVE_NEWABI)
-           {
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                          "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
+                          (int) BFD_RELOC_LO16);
+             macro_build_jalr (icnt, &offset_expr);
+
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
                {
+                 if (! mips_frame_reg_valid)
+                   {
+                     as_warn (_("No .frame pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_frame_reg_valid = 1;
+                   }
+                 if (! mips_cprestore_valid)
+                   {
+                     as_warn (_("No .cprestore pseudo-op used in PIC code"));
+                     /* Quiet this warning.  */
+                     mips_cprestore_valid = 1;
+                   }
                  if (mips_opts.noreorder)
                    macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                            "nop", "");
+                                "nop", "");
                  expr1.X_add_number = mips_cprestore_offset;
                  macro_build ((char *) NULL, &icnt, &expr1,
                               HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
-                              GP, (int) BFD_RELOC_LO16, mips_frame_reg);
+                              mips_gp_register, (int) BFD_RELOC_LO16,
+                              mips_frame_reg);
                }
            }
        }
@@ -5381,9 +5439,11 @@ macro (ip)
       if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
+         char *p;
+
          /* If this is a reference to a GP relative symbol, and there
             is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
             Otherwise, if there is no base register, we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
@@ -5393,7 +5453,7 @@ macro (ip)
             If we have a base register, and this is a reference to a
             GP relative symbol, we want
               addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
             Otherwise we want
               lui      $tempreg,<sym>          (BFD_RELOC_HI16_S)
               addu     $tempreg,$tempreg,$breg
@@ -5433,15 +5493,26 @@ macro (ip)
               dsll     $tempreg,16
               daddu    $tempreg,$tempreg,$breg
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_LO16)
+
+            If we have 64-bit addresses, as an optimization, for
+            addresses which are 32-bit constants (e.g. kseg0/kseg1
+            addresses) we fall back to the 32-bit address generation
+            mechanism since it is more efficient.  Note that due to
+            the signed offset used by memory operations, the 32-bit
+            range is shifted down by 32768 here.  This code should
+            probably attempt to generate 64-bit constants more
+            efficiently in general.
           */
-         if (HAVE_64BIT_ADDRESSES)
+         if (HAVE_64BIT_ADDRESSES
+             && !(offset_expr.X_op == O_constant
+                  && IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
            {
              p = NULL;
 
              /* We don't do GP optimization for now because RELAX_ENCODE can't
                 hold the data for such large chunks.  */
 
-             if (used_at == 0)
+             if (used_at == 0 && ! mips_opts.noat)
                {
                  macro_build (p, &icnt, &offset_expr, "lui", "t,u",
                               tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
@@ -5491,14 +5562,14 @@ macro (ip)
                {
                  frag_grow (20);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                              treg, (int) BFD_RELOC_MIPS_GPREL, GP);
+                              treg, (int) BFD_RELOC_GPREL16,
+                              mips_gp_register);
                  p = frag_var (rs_machine_dependent, 8, 0,
                                RELAX_ENCODE (4, 8, 0, 4, 0,
                                              (mips_opts.warn_about_macros
                                               || (used_at
                                                   && mips_opts.noat))),
-                               offset_expr.X_add_symbol, (offsetT) 0,
-                               (char *) NULL);
+                               offset_expr.X_add_symbol, 0, NULL);
                  used_at = 0;
                }
              macro_build_lui (p, &icnt, &offset_expr, tempreg);
@@ -5517,13 +5588,12 @@ macro (ip)
                  frag_grow (28);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                              "d,v,t", tempreg, breg, GP);
+                              "d,v,t", tempreg, breg, mips_gp_register);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                              treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                              treg, (int) BFD_RELOC_GPREL16, tempreg);
                  p = frag_var (rs_machine_dependent, 12, 0,
                                RELAX_ENCODE (8, 12, 0, 8, 0, 0),
-                               offset_expr.X_add_symbol, (offsetT) 0,
-                               (char *) NULL);
+                               offset_expr.X_add_symbol, 0, NULL);
                }
              macro_build_lui (p, &icnt, &offset_expr, tempreg);
              if (p != NULL)
@@ -5539,6 +5609,8 @@ macro (ip)
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
+         char *p;
+
          /* If this is a reference to an external symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
@@ -5562,8 +5634,8 @@ macro (ip)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          frag_grow (20);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", tempreg,
+                      (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          p = frag_var (rs_machine_dependent, 4, 0,
                        RELAX_ENCODE (0, 4, -8, 0, 0, 0),
@@ -5581,6 +5653,7 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          int gpdel;
+         char *p;
 
          /* If this is a reference to an external symbol, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
@@ -5597,14 +5670,42 @@ macro (ip)
             <op> instruction.  We don't handle constants larger than
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
-            in which we are not using $at).  */
+            in which we are not using $at).
+
+            For NewABI, we want
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
+              addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_MIPS_GOT_OFST)
+              <op>     $treg,0($tempreg)
+          */
          assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         if (reg_needs_delay (GP))
+         if (HAVE_NEWABI)
+           {
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                          "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_PAGE,
+                          mips_gp_register);
+             macro_build ((char *) NULL, &icnt, &offset_expr,
+                          HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
+                          "t,r,j", tempreg, tempreg,
+                          BFD_RELOC_MIPS_GOT_OFST);
+             if (breg != 0)
+               macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+                            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);
+
+             if (! used_at)
+               return;
+
+             break;
+           }
+         if (reg_needs_delay (mips_gp_register))
            gpdel = 4;
          else
            gpdel = 0;
@@ -5613,7 +5714,7 @@ macro (ip)
                       tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                      "d,v,t", tempreg, tempreg, GP);
+                      "d,v,t", tempreg, tempreg, mips_gp_register);
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
@@ -5628,7 +5729,8 @@ macro (ip)
            }
          macro_build (p, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16,
+                      mips_gp_register);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
          p += 4;
@@ -5645,25 +5747,25 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* If there is no base register, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
             If there is a base register, we want
               addu     $tempreg,$breg,$gp
-              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($tempreg)   (BFD_RELOC_GPREL16)
             */
          assert (offset_expr.X_op == O_symbol);
          if (breg == 0)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                          treg, (int) BFD_RELOC_MIPS_GPREL, GP);
+                          treg, (int) BFD_RELOC_GPREL16, mips_gp_register);
              used_at = 0;
            }
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                          "d,v,t", tempreg, breg, GP);
+                          "d,v,t", tempreg, breg, mips_gp_register);
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
-                          treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
+                          treg, (int) BFD_RELOC_GPREL16, tempreg);
            }
        }
       else
@@ -5699,7 +5801,7 @@ macro (ip)
                             ".lit4") == 0
                  && offset_expr.X_add_number == 0);
          macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
-                      treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
+                      treg, (int) BFD_RELOC_MIPS_LITERAL, mips_gp_register);
          return;
        }
 
@@ -5747,22 +5849,22 @@ macro (ip)
         upper 16 bits of the address.  */
       if (mips_pic == NO_PIC)
        {
-         /* FIXME: This won't work for a 64 bit address.  */
-         macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
+         macro_build_lui (NULL, &icnt, &offset_expr, AT);
        }
       else if (mips_pic == SVR4_PIC)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16,
+                      mips_gp_register);
        }
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* For embedded PIC we pick up the entire address off $gp in
             a single instruction.  */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                      "t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
+                      HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j", AT,
+                      mips_gp_register, (int) BFD_RELOC_GPREL16);
          offset_expr.X_op = O_constant;
          offset_expr.X_add_number = 0;
        }
@@ -5777,7 +5879,7 @@ macro (ip)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr, "lw", "t,o(b)",
                       treg, (int) BFD_RELOC_LO16, AT);
-         if (treg != 31)
+         if (treg != RA)
            {
              /* FIXME: How in the world do we deal with the possible
                 overflow here?  */
@@ -5835,10 +5937,11 @@ macro (ip)
          if (mips_opts.isa != ISA_MIPS1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
-                          "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
+                          "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL,
+                          mips_gp_register);
              return;
            }
-         breg = GP;
+         breg = mips_gp_register;
          r = BFD_RELOC_MIPS_LITERAL;
          goto dob;
        }
@@ -5848,11 +5951,12 @@ macro (ip)
          if (mips_pic == SVR4_PIC)
            macro_build ((char *) NULL, &icnt, &offset_expr,
                         HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                        "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
+                        "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16,
+                        mips_gp_register);
          else
            {
              /* FIXME: This won't work for a 64 bit address.  */
-             macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
+             macro_build_lui (NULL, &icnt, &offset_expr, AT);
            }
 
          if (mips_opts.isa != ISA_MIPS1)
@@ -5994,13 +6098,15 @@ macro (ip)
       if (mips_pic == NO_PIC
          || offset_expr.X_op == O_constant)
        {
+         char *p;
+
          /* If this is a reference to a GP relative symbol, we want
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
             If we have a base register, we use this
               addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
             If this is not a GP relative symbol, we want
               lui      $at,<sym>               (BFD_RELOC_HI16_S)
               <op>     $treg,<sym>($at)        (BFD_RELOC_LO16)
@@ -6021,7 +6127,7 @@ macro (ip)
              if (breg == 0)
                {
                  frag_grow (28);
-                 tempreg = GP;
+                 tempreg = mips_gp_register;
                  off = 0;
                  used_at = 0;
                }
@@ -6030,7 +6136,7 @@ macro (ip)
                  frag_grow (36);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                              "d,v,t", AT, breg, GP);
+                              "d,v,t", AT, breg, mips_gp_register);
                  tempreg = AT;
                  off = 4;
                  used_at = 1;
@@ -6039,7 +6145,7 @@ macro (ip)
              /* 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);
+                          (int) BFD_RELOC_GPREL16, tempreg);
              offset_expr.X_add_number += 4;
 
              /* Set mips_optimize to 2 to avoid inserting an
@@ -6049,14 +6155,13 @@ macro (ip)
              /* 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);
+                          (int) BFD_RELOC_GPREL16, tempreg);
              mips_optimize = hold_mips_optimize;
 
              p = frag_var (rs_machine_dependent, 12 + off, 0,
                            RELAX_ENCODE (8 + off, 12 + off, 0, 4 + off, 1,
                                          used_at && mips_opts.noat),
-                           offset_expr.X_add_symbol, (offsetT) 0,
-                           (char *) NULL);
+                           offset_expr.X_add_symbol, 0, NULL);
 
              /* We just generated two relocs.  When tc_gen_reloc
                 handles this case, it will skip the first reloc and
@@ -6132,8 +6237,8 @@ macro (ip)
            off = 4;
          frag_grow (24 + off);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", AT,
+                      (int) BFD_RELOC_MIPS_GOT16, mips_gp_register);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -6162,6 +6267,7 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          int gpdel, off;
+         char *p;
 
          /* If this is a reference to an external symbol, we want
               lui      $at,<sym>               (BFD_RELOC_MIPS_GOT_HI16)
@@ -6184,7 +6290,7 @@ macro (ip)
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
-         if (reg_needs_delay (GP))
+         if (reg_needs_delay (mips_gp_register))
            gpdel = 4;
          else
            gpdel = 0;
@@ -6197,7 +6303,7 @@ macro (ip)
                       AT, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                      "d,v,t", AT, AT, GP);
+                      "d,v,t", AT, AT, mips_gp_register);
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT_LO16, AT);
@@ -6234,7 +6340,8 @@ macro (ip)
            }
          macro_build (p, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16,
+                      mips_gp_register);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
          p += 4;
@@ -6265,23 +6372,23 @@ macro (ip)
       else if (mips_pic == EMBEDDED_PIC)
        {
          /* If there is no base register, we use
-              <op>     $treg,<sym>($gp)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($gp)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($gp)    (BFD_RELOC_GPREL16)
             If we have a base register, we use
               addu     $at,$breg,$gp
-              <op>     $treg,<sym>($at)        (BFD_RELOC_MIPS_GPREL)
-              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_MIPS_GPREL)
+              <op>     $treg,<sym>($at)        (BFD_RELOC_GPREL16)
+              <op>     $treg+1,<sym>+4($at)    (BFD_RELOC_GPREL16)
             */
          if (breg == 0)
            {
-             tempreg = GP;
+             tempreg = mips_gp_register;
              used_at = 0;
            }
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-                          "d,v,t", AT, breg, GP);
+                          "d,v,t", AT, breg, mips_gp_register);
              tempreg = AT;
              used_at = 1;
            }
@@ -6289,12 +6396,12 @@ macro (ip)
          /* 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);
+                      (int) BFD_RELOC_GPREL16, tempreg);
          offset_expr.X_add_number += 4;
          /* 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);
+                      (int) BFD_RELOC_GPREL16, tempreg);
        }
       else
        abort ();
@@ -6462,12 +6569,12 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
                   dreg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                  dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, 31);
+                  dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, RA);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mfhi", "d",
                   AT);
       if (mips_trap)
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
-                    dreg, AT);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne",
+                    "s,t,q", dreg, AT, 6);
       else
        {
          expr1.X_add_number = 8;
@@ -6505,8 +6612,8 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "mflo", "d",
                   dreg);
       if (mips_trap)
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne", "s,t",
-                    AT, 0);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "tne",
+                    "s,t,q", AT, 0, 6);
       else
        {
          expr1.X_add_number = 8;
@@ -6519,6 +6626,17 @@ macro2 (ip)
       --mips_opts.noreorder;
       break;
 
+    case M_DROL:
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsubu",
+                  "d,v,t", AT, 0, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsrlv",
+                  "d,t,s", AT, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsllv",
+                  "d,t,s", dreg, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                  "d,v,t", dreg, dreg, AT);
+      break;
+
     case M_ROL:
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "subu",
                   "d,v,t", AT, 0, treg);
@@ -6530,15 +6648,55 @@ macro2 (ip)
                   "d,v,t", dreg, dreg, AT);
       break;
 
+    case M_DROL_I:
+      {
+       unsigned int rot;
+       char *l, *r;
+
+       if (imm_expr.X_op != O_constant)
+         as_bad (_("rotate count too large"));
+       rot = imm_expr.X_add_number & 0x3f;
+       if (! rot)
+         break;
+       l = (rot < 0x20) ? "dsll" : "dsll32";
+       r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
+       rot &= 0x1f;
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, l,
+                    "d,w,<", AT, sreg, rot);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, r,
+                    "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                    "d,v,t", dreg, dreg, AT);
+      }
+      break;
+
     case M_ROL_I:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("rotate count too large"));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
-                  AT, sreg, (int) (imm_expr.X_add_number & 0x1f));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
-                  dreg, sreg, (int) ((0 - imm_expr.X_add_number) & 0x1f));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
-                  dreg, dreg, AT);
+      {
+       unsigned int rot;
+
+       if (imm_expr.X_op != O_constant)
+         as_bad (_("rotate count too large"));
+       rot = imm_expr.X_add_number & 0x1f;
+       if (! rot)
+         break;
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll",
+                    "d,w,<", AT, sreg, rot);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
+                    "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                    "d,v,t", dreg, dreg, AT);
+      }
+      break;
+
+    case M_DROR:
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsubu",
+                  "d,v,t", AT, 0, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsllv",
+                  "d,t,s", AT, sreg, AT);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsrlv",
+                  "d,t,s", dreg, sreg, treg);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                  "d,v,t", dreg, dreg, AT);
       break;
 
     case M_ROR:
@@ -6552,15 +6710,44 @@ macro2 (ip)
                   "d,v,t", dreg, dreg, AT);
       break;
 
+    case M_DROR_I:
+      {
+       unsigned int rot;
+       char *l, *r;
+
+       if (imm_expr.X_op != O_constant)
+         as_bad (_("rotate count too large"));
+       rot = imm_expr.X_add_number & 0x3f;
+       if (! rot)
+         break;
+       r = (rot < 0x20) ? "dsrl" : "dsrl32";
+       l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
+       rot &= 0x1f;
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, r,
+                    "d,w,<", AT, sreg, rot);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, l,
+                    "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                    "d,v,t", dreg, dreg, AT);
+      }
+      break;
+
     case M_ROR_I:
-      if (imm_expr.X_op != O_constant)
-       as_bad (_("rotate count too large"));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
-                  AT, sreg, (int) (imm_expr.X_add_number & 0x1f));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
-                  dreg, sreg, (int) ((0 - imm_expr.X_add_number) & 0x1f));
-      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or", "d,v,t",
-                  dreg, dreg, AT);
+      {
+       unsigned int rot;
+
+       if (imm_expr.X_op != O_constant)
+         as_bad (_("rotate count too large"));
+       rot = imm_expr.X_add_number & 0x1f;
+       if (! rot)
+         break;
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
+                    "d,w,<", AT, sreg, rot);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll",
+                    "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "or",
+                    "d,v,t", dreg, dreg, AT);
+      }
       break;
 
     case M_S_DOB:
@@ -6632,7 +6819,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, 0);
+         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
                       "d,v,t", dreg, sreg, AT);
          used_at = 1;
@@ -6668,7 +6855,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, 0);
+         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       mask == M_SGE_I ? "slt" : "sltu", "d,v,t", dreg, sreg,
                       AT);
@@ -6696,7 +6883,7 @@ macro2 (ip)
     case M_SGTU_I:
       s = "sltu";
     sgti:
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
                   dreg, AT, sreg);
       break;
@@ -6719,7 +6906,7 @@ macro2 (ip)
     case M_SLEU_I:
       s = "sltu";
     slei:
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t",
                   dreg, AT, sreg);
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", dreg, dreg,
@@ -6735,7 +6922,7 @@ macro2 (ip)
                       dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "slt", "d,v,t",
                   dreg, sreg, AT);
       break;
@@ -6749,7 +6936,7 @@ macro2 (ip)
                       dreg, sreg, (int) BFD_RELOC_LO16);
          return;
        }
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sltu",
                   "d,v,t", dreg, sreg, AT);
       break;
@@ -6806,7 +6993,7 @@ macro2 (ip)
        }
       else
        {
-         load_register (&icnt, AT, &imm_expr, 0);
+         load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "xor",
                       "d,v,t", dreg, sreg, AT);
          used_at = 1;
@@ -6871,7 +7058,7 @@ macro2 (ip)
     case M_TNE_I:
       s = "tne";
     trap:
-      load_register (&icnt, AT, &imm_expr, 0);
+      load_register (&icnt, AT, &imm_expr, HAVE_64BIT_GPRS);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "s,t", sreg,
                   AT);
       break;
@@ -6890,9 +7077,9 @@ macro2 (ip)
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "cfc1", "t,G",
-                  treg, 31);
+                  treg, RA);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "cfc1", "t,G",
-                  treg, 31);
+                  treg, RA);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
       expr1.X_add_number = 3;
       macro_build ((char *) NULL, &icnt, &expr1, "ori", "t,r,i", AT, treg,
@@ -6901,12 +7088,12 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, &expr1, "xori", "t,r,i", AT, AT,
                     (int) BFD_RELOC_LO16);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "ctc1", "t,G",
-                  AT, 31);
+                  AT, RA);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
              mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S", dreg, sreg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "ctc1", "t,G",
-                  treg, 31);
+                  treg, RA);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
       --mips_opts.noreorder;
       break;
@@ -6921,13 +7108,13 @@ macro2 (ip)
        as_bad (_("operand overflow"));
       /* avoid load delay */
       if (! target_big_endian)
-       offset_expr.X_add_number += 1;
+       ++offset_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, breg);
       if (! target_big_endian)
-       offset_expr.X_add_number -= 1;
+       --offset_expr.X_add_number;
       else
-       offset_expr.X_add_number += 1;
+       ++offset_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &offset_expr, "lbu", "t,o(b)", AT,
                   (int) BFD_RELOC_LO16, breg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll", "d,w,<",
@@ -6971,7 +7158,7 @@ macro2 (ip)
       off = 3;
     ulwa:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at);
+      load_address (&icnt, AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                     HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
@@ -6993,7 +7180,7 @@ macro2 (ip)
     case M_ULH_A:
     case M_ULHU_A:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at);
+      load_address (&icnt, AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                     HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
@@ -7019,15 +7206,15 @@ macro2 (ip)
       if (offset_expr.X_add_number >= 0x7fff)
        as_bad (_("operand overflow"));
       if (target_big_endian)
-       offset_expr.X_add_number += 1;
+       ++offset_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &offset_expr, "sb", "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, breg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl", "d,w,<",
                   AT, treg, 8);
       if (target_big_endian)
-       offset_expr.X_add_number -= 1;
+       --offset_expr.X_add_number;
       else
-       offset_expr.X_add_number += 1;
+       ++offset_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &offset_expr, "sb", "t,o(b)", AT,
                   (int) BFD_RELOC_LO16, breg);
       break;
@@ -7067,7 +7254,7 @@ macro2 (ip)
       off = 3;
     uswa:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at);
+      load_address (&icnt, AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                     HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
@@ -7088,7 +7275,7 @@ macro2 (ip)
 
     case M_USH_A:
       used_at = 1;
-      load_address (&icnt, AT, &offset_expr, HAVE_64BIT_ADDRESSES, &used_at);
+      load_address (&icnt, AT, &offset_expr, &used_at);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                     HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
@@ -7212,8 +7399,8 @@ mips16_macro (ip)
                   xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
-                    "6", 7);
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "break",
+                  "6", 7);
       --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s2, "x", zreg);
       break;
@@ -7368,7 +7555,7 @@ mips16_macro (ip)
 
     case M_ABS:
       expr1.X_add_number = 0;
-      macro_build ((char *) NULL, &icnt, &expr1, "slti", "x,8",  yreg);
+      macro_build ((char *) NULL, &icnt, &expr1, "slti", "x,8", yreg);
       if (xreg != yreg)
        move_register (&icnt, xreg, yreg);
       expr1.X_add_number = 2;
@@ -7417,11 +7604,17 @@ validate_mips_insn (opc)
       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;
+      case 'O':        USE_BITS (OP_MASK_ALN,          OP_SH_ALN);     break;
+      case 'Q':        USE_BITS (OP_MASK_VSEL,         OP_SH_VSEL);
+               USE_BITS (OP_MASK_FT,           OP_SH_FT);      break;
       case 'R':        USE_BITS (OP_MASK_FR,           OP_SH_FR);      break;
       case 'S':        USE_BITS (OP_MASK_FS,           OP_SH_FS);      break;
       case 'T':        USE_BITS (OP_MASK_FT,           OP_SH_FT);      break;
       case 'V':        USE_BITS (OP_MASK_FS,           OP_SH_FS);      break;
       case 'W':        USE_BITS (OP_MASK_FT,           OP_SH_FT);      break;
+      case 'X':        USE_BITS (OP_MASK_FD,           OP_SH_FD);      break;
+      case 'Y':        USE_BITS (OP_MASK_FS,           OP_SH_FS);      break;
+      case 'Z':        USE_BITS (OP_MASK_FT,           OP_SH_FT);      break;
       case 'a':        USE_BITS (OP_MASK_TARGET,       OP_SH_TARGET);  break;
       case 'b':        USE_BITS (OP_MASK_RS,           OP_SH_RS);      break;
       case 'c':        USE_BITS (OP_MASK_CODE,         OP_SH_CODE);    break;
@@ -7480,7 +7673,6 @@ mips_ip (str, ip)
   unsigned int lastregno = 0;
   char *s_reset;
   char save_c = 0;
-  int full_opcode_match = 1;
 
   insn_error = NULL;
 
@@ -7530,8 +7722,6 @@ mips_ip (str, ip)
          insn_error = "unrecognized opcode";
          return;
        }
-
-      full_opcode_match = 0;
     }
 
   argsStart = s;
@@ -7541,7 +7731,12 @@ mips_ip (str, ip)
 
       assert (strcmp (insn->name, str) == 0);
 
-      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_arch))
+      if (OPCODE_IS_MEMBER (insn,
+                           (mips_opts.isa
+                            | (mips_opts.mips16 ? INSN_MIPS16 : 0)
+                            | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
+                            | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)),
+                           mips_arch))
        ok = true;
       else
        ok = false;
@@ -7565,11 +7760,15 @@ mips_ip (str, ip)
              if (!insn_error)
                {
                  static char buf[100];
-                 sprintf (buf,
-                          _("opcode not supported on this processor: %s (%s)"),
-                          mips_cpu_to_str (mips_arch),
-                          mips_isa_to_str (mips_opts.isa));
-
+                 if (mips_arch_info->is_isa)
+                   sprintf (buf,
+                            _("opcode not supported at this ISA level (%s)"),
+                            mips_cpu_info_from_isa (mips_opts.isa)->name);
+                 else
+                   sprintf (buf,
+                            _("opcode not supported on this processor: %s (%s)"),
+                            mips_arch_info->name,
+                            mips_cpu_info_from_isa (mips_opts.isa)->name);
                  insn_error = buf;
                }
              if (save_c)
@@ -7583,7 +7782,10 @@ mips_ip (str, ip)
       insn_error = NULL;
       for (args = insn->args;; ++args)
        {
+         int is_mdmx;
+
          s += strspn (s, " \t");
+         is_mdmx = 0;
          switch (*args)
            {
            case '\0':          /* end of args */
@@ -7643,8 +7845,8 @@ mips_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
                {
-                 as_warn (_("Improper shift amount (%ld)"),
-                          (long) imm_expr.X_add_number);
+                 as_warn (_("Improper shift amount (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_SHAMT;
                }
              ip->insn_opcode |= imm_expr.X_add_number << OP_SH_SHAMT;
@@ -7685,10 +7887,10 @@ mips_ip (str, ip)
            case 'c':           /* break code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned) imm_expr.X_add_number > 1023)
+             if ((unsigned long) imm_expr.X_add_number > 1023)
                {
-                 as_warn (_("Illegal break code (%ld)"),
-                          (long) imm_expr.X_add_number);
+                 as_warn (_("Illegal break code (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_CODE;
                }
              ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE;
@@ -7699,10 +7901,10 @@ mips_ip (str, ip)
            case 'q':           /* lower break code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned) imm_expr.X_add_number > 1023)
+             if ((unsigned long) imm_expr.X_add_number > 1023)
                {
-                 as_warn (_("Illegal lower break code (%ld)"),
-                          (long) imm_expr.X_add_number);
+                 as_warn (_("Illegal lower break code (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_CODE2;
                }
              ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE2;
@@ -7713,22 +7915,22 @@ mips_ip (str, ip)
            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 > OP_MASK_CODE20)
-               as_warn (_("Illegal 20-bit code (%ld)"),
-                        (long) imm_expr.X_add_number);
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
+               as_warn (_("Illegal 20-bit code (%lu)"),
+                        (unsigned long) imm_expr.X_add_number);
              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 */
+           case 'C':           /* Coprocessor code */
              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)"),
-                          (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number &= ((1<<25) - 1);
+                 as_warn (_("Coproccesor code > 25 bits (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
+                 imm_expr.X_add_number &= ((1 << 25) - 1);
                }
              ip->insn_opcode |= imm_expr.X_add_number;
              imm_expr.X_op = O_absent;
@@ -7738,9 +7940,9 @@ mips_ip (str, ip)
            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);
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
+               as_warn (_("Illegal 19-bit code (%lu)"),
+                        (unsigned 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;
@@ -7751,8 +7953,8 @@ mips_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                {
-                 as_warn (_("Invalid performance register (%ld)"),
-                          (long) imm_expr.X_add_number);
+                 as_warn (_("Invalid performance register (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_PERFREG;
                }
              ip->insn_opcode |= (imm_expr.X_add_number << OP_SH_PERFREG);
@@ -7794,7 +7996,12 @@ mips_ip (str, ip)
                    goto notreg;
                  else
                    {
-                     if (s[1] == 'f' && s[2] == 'p')
+                     if (s[1] == 'r' && s[2] == 'a')
+                       {
+                         s += 3;
+                         regno = RA;
+                       }
+                     else if (s[1] == 'f' && s[2] == 'p')
                        {
                          s += 3;
                          regno = FP;
@@ -7824,6 +8031,11 @@ mips_ip (str, ip)
                          s += 4;
                          regno = KT1;
                        }
+                     else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+                       {
+                         s += 5;
+                         regno = ZERO;
+                       }
                      else if (itbl_have_entries)
                        {
                          char *p, *n;
@@ -7858,14 +8070,14 @@ mips_ip (str, ip)
                    as_warn (_("Used $at without \".set noat\""));
                  c = *args;
                  if (*s == ' ')
-                   s++;
+                   ++s;
                  if (args[1] != *s)
                    {
                      if (c == 'r' || c == 'v' || c == 'w')
                        {
                          regno = lastregno;
                          s = s_reset;
-                         args++;
+                         ++args;
                        }
                    }
                  /* 'z' only matches $0.  */
@@ -7932,6 +8144,47 @@ mips_ip (str, ip)
                }
              break;
 
+           case 'O':           /* MDMX alignment immediate constant.  */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
+               {
+                 as_warn ("Improper align amount (%ld), using low bits",
+                          (long) imm_expr.X_add_number);
+                 imm_expr.X_add_number &= OP_MASK_ALN;
+               }
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_ALN;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case 'Q':           /* MDMX vector, element sel, or const.  */
+             if (s[0] != '$')
+               {
+                 /* MDMX Immediate.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned long) imm_expr.X_add_number > OP_MASK_FT)
+                   {
+                     as_warn (_("Invalid MDMX Immediate (%ld)"),
+                              (long) imm_expr.X_add_number);
+                     imm_expr.X_add_number &= OP_MASK_FT;
+                   }
+                 imm_expr.X_add_number &= OP_MASK_FT;
+                 if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
+                   ip->insn_opcode |= MDMX_FMTSEL_IMM_QH << OP_SH_VSEL;
+                 else
+                   ip->insn_opcode |= MDMX_FMTSEL_IMM_OB << OP_SH_VSEL;
+                 ip->insn_opcode |= imm_expr.X_add_number << OP_SH_FT;
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+               }
+             /* Not MDMX Immediate.  Fall through.  */
+           case 'X':           /* MDMX destination register.  */
+           case 'Y':           /* MDMX source register.  */
+           case 'Z':           /* MDMX target register.  */
+             is_mdmx = 1;
            case 'D':           /* floating point destination register */
            case 'S':           /* floating point source register */
            case 'T':           /* floating point target register */
@@ -7939,8 +8192,11 @@ mips_ip (str, ip)
            case 'V':
            case 'W':
              s_reset = s;
-             if (s[0] == '$' && s[1] == 'f'
-                 && ISDIGIT (s[2]))
+             /* Accept $fN for FP and MDMX register numbers, and in
+                 addition accept $vN for MDMX register numbers.  */
+             if ((s[0] == '$' && s[1] == 'f' && ISDIGIT (s[2]))
+                 || (is_mdmx != 0 && s[0] == '$' && s[1] == 'v'
+                     && ISDIGIT (s[2])))
                {
                  s += 2;
                  regno = 0;
@@ -7968,27 +8224,64 @@ mips_ip (str, ip)
 
                  c = *args;
                  if (*s == ' ')
-                   s++;
+                   ++s;
                  if (args[1] != *s)
                    {
                      if (c == 'V' || c == 'W')
                        {
                          regno = lastregno;
                          s = s_reset;
-                         args++;
+                         ++args;
                        }
                    }
                  switch (c)
                    {
                    case 'D':
+                   case 'X':
                      ip->insn_opcode |= regno << OP_SH_FD;
                      break;
                    case 'V':
                    case 'S':
+                   case 'Y':
                      ip->insn_opcode |= regno << OP_SH_FS;
                      break;
+                   case 'Q':
+                     /* This is like 'Z', but also needs to fix the MDMX
+                        vector/scalar select bits.  Note that the
+                        scalar immediate case is handled above.  */
+                     if (*s == '[')
+                       {
+                         int is_qh = (ip->insn_opcode & (1 << OP_SH_VSEL));
+                         int max_el = (is_qh ? 3 : 7);
+                         s++;
+                         my_getExpression(&imm_expr, s);
+                         check_absolute_expr (ip, &imm_expr);
+                         s = expr_end;
+                         if (imm_expr.X_add_number > max_el)
+                           as_bad(_("Bad element selector %ld"),
+                                  (long) imm_expr.X_add_number);
+                         imm_expr.X_add_number &= max_el;
+                         ip->insn_opcode |= (imm_expr.X_add_number
+                                             << (OP_SH_VSEL +
+                                                 (is_qh ? 2 : 1)));
+                         if (*s != ']')
+                           as_warn(_("Expecting ']' found '%s'"), s);
+                         else
+                           s++;
+                       }
+                     else
+                        {
+                          if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
+                            ip->insn_opcode |= (MDMX_FMTSEL_VEC_QH
+                                               << OP_SH_VSEL);
+                         else
+                           ip->insn_opcode |= (MDMX_FMTSEL_VEC_OB <<
+                                               OP_SH_VSEL);
+                       }
+                      /* Fall through */
                    case 'W':
                    case 'T':
+                   case 'Z':
                      ip->insn_opcode |= regno << OP_SH_FT;
                      break;
                    case 'R':
@@ -8238,14 +8531,16 @@ mips_ip (str, ip)
                {
                  if (c != S_EX_LO)
                    {
-                     if (imm_expr.X_op == O_constant)
-                       imm_expr.X_add_number =
-                         (imm_expr.X_add_number >> 16) & 0xffff;
+                     if (c == S_EX_HI)
+                       {
+                         *imm_reloc = BFD_RELOC_HI16_S;
+                         imm_unmatched_hi = true;
+                       }
 #ifdef OBJ_ELF
                      else if (c == S_EX_HIGHEST)
-                         *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+                       *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
                      else if (c == S_EX_HIGHER)
-                         *imm_reloc = BFD_RELOC_MIPS_HIGHER;
+                       *imm_reloc = BFD_RELOC_MIPS_HIGHER;
                      else if (c == S_EX_GP_REL)
                        {
                          /* This occurs in NewABI only.  */
@@ -8266,11 +8561,6 @@ mips_ip (str, ip)
                            }
                        }
 #endif
-                     else if (c == S_EX_HI)
-                       {
-                         *imm_reloc = BFD_RELOC_HI16_S;
-                         imm_unmatched_hi = true;
-                       }
                      else
                        *imm_reloc = BFD_RELOC_HI16;
                    }
@@ -8371,17 +8661,14 @@ mips_ip (str, ip)
                {
                  if (c != S_EX_LO)
                    {
-                     if (imm_expr.X_op == O_constant)
-                       imm_expr.X_add_number =
-                         (imm_expr.X_add_number >> 16) & 0xffff;
-                     else if (c == S_EX_HI)
+                     if (c == S_EX_HI)
                        {
                          *imm_reloc = BFD_RELOC_HI16_S;
                          imm_unmatched_hi = true;
                        }
 #ifdef OBJ_ELF
                      else if (c == S_EX_HIGHEST)
-                         *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
+                       *imm_reloc = BFD_RELOC_MIPS_HIGHEST;
                      else if (c == S_EX_GP_REL)
                        {
                          /* This occurs in NewABI only.  */
@@ -8408,9 +8695,9 @@ mips_ip (str, ip)
                  else if (imm_expr.X_op == O_constant)
                    imm_expr.X_add_number &= 0xffff;
                }
-             if (imm_expr.X_op == O_constant
-                 && (imm_expr.X_add_number < 0
-                     || imm_expr.X_add_number >= 0x10000))
+             else if (imm_expr.X_op == O_constant
+                      && (imm_expr.X_add_number < 0
+                          || imm_expr.X_add_number >= 0x10000))
                as_bad (_("lui expression not in range 0..65535"));
              s = expr_end;
              continue;
@@ -8666,7 +8953,12 @@ mips16_ip (str, ip)
                }
              else
                {
-                 if (s[1] == 'f' && s[2] == 'p')
+                 if (s[1] == 'r' && s[2] == 'a')
+                   {
+                     s += 3;
+                     regno = RA;
+                   }
+                 else if (s[1] == 'f' && s[2] == 'p')
                    {
                      s += 3;
                      regno = FP;
@@ -8696,6 +8988,11 @@ mips16_ip (str, ip)
                      s += 4;
                      regno = KT1;
                    }
+                 else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+                   {
+                     s += 5;
+                     regno = ZERO;
+                   }
                  else
                    break;
                }
@@ -8708,7 +9005,7 @@ mips16_ip (str, ip)
                    {
                      regno = mips16_to_32_reg_map[lastregno];
                      s = s_reset;
-                     args++;
+                     ++args;
                    }
                }
 
@@ -8976,7 +9273,7 @@ mips16_ip (str, ip)
                      mask |= (reg2 - 3) << 3;
                    else if (reg1 == 16 && reg2 >= 16 && reg2 <= 17)
                      mask |= (reg2 - 15) << 1;
-                   else if (reg1 == 31 && reg2 == 31)
+                   else if (reg1 == RA && reg2 == RA)
                      mask |= 1;
                    else
                      {
@@ -9208,26 +9505,24 @@ static struct percent_op_match
    const enum small_ex_type type;
 } percent_op[] =
 {
-#ifdef OBJ_ELF
-  {"%half", S_EX_HALF},
-#endif
-  {"%hi", S_EX_HI},
   {"%lo", S_EX_LO},
 #ifdef OBJ_ELF
-  {"%gp_rel", S_EX_GP_REL},
-  {"%got", S_EX_GOT},
+  {"%call_hi", S_EX_CALL_HI},
+  {"%call_lo", S_EX_CALL_LO},
   {"%call16", S_EX_CALL16},
   {"%got_disp", S_EX_GOT_DISP},
   {"%got_page", S_EX_GOT_PAGE},
   {"%got_ofst", S_EX_GOT_OFST},
   {"%got_hi", S_EX_GOT_HI},
   {"%got_lo", S_EX_GOT_LO},
-  {"%neg", S_EX_NEG},
-  {"%higher", S_EX_HIGHER},
+  {"%got", S_EX_GOT},
+  {"%gp_rel", S_EX_GP_REL},
+  {"%half", S_EX_HALF},
   {"%highest", S_EX_HIGHEST},
-  {"%call_hi", S_EX_CALL_HI},
-  {"%call_lo", S_EX_CALL_LO}
+  {"%higher", S_EX_HIGHER},
+  {"%neg", S_EX_NEG},
 #endif
+  {"%hi", S_EX_HI}
 };
 
 /* Parse small expression input.  STR gets adjusted to eat up whitespace.
@@ -9241,10 +9536,9 @@ my_getSmallParser (str, len, nestlevel)
      unsigned int *len;
      int *nestlevel;
 {
-  int type = S_EX_NONE;
-
   *len = 0;
   *str += strspn (*str, " \t");
+  /* Check for expression in parentheses.  */
   if (**str == '(')
     {
       char *b = *str + 1 + strspn (*str + 1, " \t");
@@ -9257,64 +9551,82 @@ my_getSmallParser (str, len, nestlevel)
              && (e = b + strcspn (b, ") \t"))
              && e - b > 1 && e - b < 4)
            {
-              if ((e - b == 3
-                   && ((b[1] == 'f' && b[2] == 'p')
-                       || (b[1] == 's' && b[2] == 'p')
-                       || (b[1] == 'g' && b[2] == 'p')
-                       || (b[1] == 'a' && b[2] == 't')
-                       || (ISDIGIT (b[1])
-                           && ISDIGIT (b[2]))))
-                  || (ISDIGIT (b[1])))
-                {
-                  *len = strcspn (*str, ")") + 1;
-                  return S_EX_REGISTER;
-                }
+             if ((e - b == 3
+                  && ((b[1] == 'f' && b[2] == 'p')
+                      || (b[1] == 's' && b[2] == 'p')
+                      || (b[1] == 'g' && b[2] == 'p')
+                      || (b[1] == 'a' && b[2] == 't')
+                      || (ISDIGIT (b[1])
+                          && ISDIGIT (b[2]))))
+                 || (ISDIGIT (b[1])))
+               {
+                 *len = strcspn (*str, ")") + 1;
+                 return S_EX_REGISTER;
+               }
            }
        }
+      /* Check for percent_op (in parentheses).  */
       else if (b[0] == '%')
        {
          *str = b;
-         goto percent_op;
+         return my_getPercentOp (str, len, nestlevel);
        }
 
-      /* Some other expression in the braces.  */
-      *len = strcspn (*str, ")") + 1;
+      /* Some other expression in the parentheses, which can contain
+        parentheses itself. Attempt to find the matching one.  */
+      {
+       int pcnt = 1;
+       char *s;
+
+       *len = 1;
+       for (s = *str + 1; *s && pcnt; s++, (*len)++)
+         {
+           if (*s == '(')
+             ++pcnt;
+           else if (*s == ')')
+             --pcnt;
+         }
+      }
     }
-  /* Check for percent_op.  */
+  /* Check for percent_op (outside of parentheses).  */
   else if (*str[0] == '%')
-    {
-      char *tmp;
-      unsigned int i;
+    return my_getPercentOp (str, len, nestlevel);
 
-percent_op:
-      tmp = *str + 1;
-      i = 0;
+  /* Any other expression.  */
+  return S_EX_NONE;
+}
 
-      while (ISALPHA (*tmp) || *tmp == '_')
-       {
-         *tmp = TOLOWER (*tmp);
-         tmp++;
-       }
-      while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+static int
+my_getPercentOp (str, len, nestlevel)
+     char **str;
+     unsigned int *len;
+     int *nestlevel;
+{
+  char *tmp = *str + 1;
+  unsigned int i = 0;
+
+  while (ISALPHA (*tmp) || *tmp == '_')
+    {
+      *tmp = TOLOWER (*tmp);
+      tmp++;
+    }
+  while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
+    {
+      if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
+       i++;
+      else
        {
-         if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
-             i++;
-         else
-           {
-             type = percent_op[i].type;
+         int type = percent_op[i].type;
 
-             /* Only %hi and %lo are allowed for OldABI.  */
-             if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
-               return S_EX_NONE;
+         /* Only %hi and %lo are allowed for OldABI.  */
+         if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
+           return S_EX_NONE;
 
-             *len = strlen (percent_op[i].str);
-             (*nestlevel)++;
-             return type;
-           }
+         *len = strlen (percent_op[i].str);
+         ++(*nestlevel);
+         return type;
        }
     }
-
-  /* Any other expression.  */
   return S_EX_NONE;
 }
 
@@ -9326,46 +9638,59 @@ my_getSmallExpression (ep, str)
   static char *oldstr = NULL;
   int c = S_EX_NONE;
   int oldc;
-  int nest_level = 0;
+  int nestlevel = -1;
   unsigned int len;
 
-  /* Don't update oldstr if the last call had nested percent_op's.  */
+  /* Don't update oldstr if the last call had nested percent_op's. We need
+     it to parse the outer ones later.  */
   if (! oldstr)
     oldstr = str;
 
   do
     {
       oldc = c;
-      c = my_getSmallParser (&str, &len, &nest_level);
+      c = my_getSmallParser (&str, &len, &nestlevel);
       if (c != S_EX_NONE && c != S_EX_REGISTER)
        str += len;
     }
   while (c != S_EX_NONE && c != S_EX_REGISTER);
 
-  /* A percent_op was encountered.  */
-  if (nest_level)
+  if (nestlevel >= 0)
     {
-      /* Don't try to get an expression if it is already blanked out.  */
+      /* A percent_op was encountered.  Don't try to get an expression if
+        it is already blanked out.  */
       if (*(str + strspn (str + 1, " )")) != ')')
        {
          char save;
 
+         /* Let my_getExpression() stop at the closing parenthesis.  */
          save = *(str + len);
          *(str + len) = '\0';
          my_getExpression (ep, str);
          *(str + len) = save;
        }
-      if (nest_level > 1)
+      if (nestlevel > 0)
        {
-         /* blank out including the % sign.  */
-         char *p = strrchr (oldstr, '%');
-         memset (p, ' ', str - p + len);
+         /* Blank out including the % sign and the proper matching
+            parenthesis.  */
+         int pcnt = 1;
+         char *s = strrchr (oldstr, '%');
+         char *end;
+
+         for (end = strchr (s, '(') + 1; *end && pcnt; end++)
+           {
+             if (*end == '(')
+               ++pcnt;
+             else if (*end == ')')
+               --pcnt;
+           }
+
+         memset (s, ' ', end - s);
          str = oldstr;
        }
       else
-       {
-         expr_end = strchr (str, ')') + 1;
-       }
+       expr_end = str + len;
+
       c = oldc;
     }
   else if (c == S_EX_NONE)
@@ -9382,10 +9707,11 @@ my_getSmallExpression (ep, str)
     }
   else
     {
-      as_fatal(_("internal error"));
+      as_fatal (_("internal error"));
     }
 
-  if (nest_level <= 1)
+  if (nestlevel <= 0)
+    /* All percent_op's have been handled.  */
     oldstr = NULL;
 
   return c;
@@ -9509,7 +9835,7 @@ static int support_64bit_objects(void)
 }
 #endif /* OBJ_ELF */
 
-CONST char *md_shortopts = "nO::g::G:";
+const char *md_shortopts = "nO::g::G:";
 
 struct option md_longopts[] =
 {
@@ -9546,8 +9872,9 @@ struct option md_longopts[] =
   {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
 #define OPTION_M7000_HILO_FIX (OPTION_MD_BASE + 15)
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-#define OPTION_NO_M7000_HILO_FIX (OPTION_MD_BASE + 16)
-  {"no-fix-7000", no_argument, NULL, OPTION_NO_M7000_HILO_FIX},
+#define OPTION_MNO_7000_HILO_FIX (OPTION_MD_BASE + 16)
+  {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
 #define OPTION_FP32 (OPTION_MD_BASE + 17)
   {"mfp32", no_argument, NULL, OPTION_FP32},
 #define OPTION_GP32 (OPTION_MD_BASE + 18)
@@ -9560,8 +9887,8 @@ struct option md_longopts[] =
   {"march", required_argument, NULL, OPTION_MARCH},
 #define OPTION_MTUNE (OPTION_MD_BASE + 22)
   {"mtune", required_argument, NULL, OPTION_MTUNE},
-#define OPTION_MCPU (OPTION_MD_BASE + 23)
-  {"mcpu", required_argument, NULL, OPTION_MCPU},
+#define OPTION_FP64 (OPTION_MD_BASE + 23)
+  {"mfp64", no_argument, NULL, OPTION_FP64},
 #define OPTION_M4650 (OPTION_MD_BASE + 24)
   {"m4650", no_argument, NULL, OPTION_M4650},
 #define OPTION_NO_M4650 (OPTION_MD_BASE + 25)
@@ -9580,8 +9907,16 @@ struct option md_longopts[] =
   {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
 #define OPTION_GP64 (OPTION_MD_BASE + 32)
   {"mgp64", no_argument, NULL, OPTION_GP64},
+#define OPTION_MIPS3D (OPTION_MD_BASE + 33)
+  {"mips3d", no_argument, NULL, OPTION_MIPS3D},
+#define OPTION_NO_MIPS3D (OPTION_MD_BASE + 34)
+  {"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
+#define OPTION_MDMX (OPTION_MD_BASE + 35)
+  {"mdmx", no_argument, NULL, OPTION_MDMX},
+#define OPTION_NO_MDMX (OPTION_MD_BASE + 36)
+  {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MD_BASE + 33)
+#define OPTION_ELF_BASE    (OPTION_MD_BASE + 37)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
@@ -9597,11 +9932,33 @@ struct option md_longopts[] =
   {"n32",         no_argument, NULL, OPTION_N32},
 #define OPTION_64          (OPTION_ELF_BASE + 6)
   {"64",          no_argument, NULL, OPTION_64},
+#define OPTION_MDEBUG      (OPTION_ELF_BASE + 7)
+  {"mdebug", no_argument, NULL, OPTION_MDEBUG},
+#define OPTION_NO_MDEBUG   (OPTION_ELF_BASE + 8)
+  {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
 #endif /* OBJ_ELF */
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
 
+/* Set STRING_PTR (either &mips_arch_string or &mips_tune_string) to
+   NEW_VALUE.  Warn if another value was already specified.  Note:
+   we have to defer parsing the -march and -mtune arguments in order
+   to handle 'from-abi' correctly, since the ABI might be specified
+   in a later argument.  */
+
+static void
+mips_set_option_string (string_ptr, new_value)
+     const char **string_ptr, *new_value;
+{
+  if (*string_ptr != 0 && strcasecmp (*string_ptr, new_value) != 0)
+    as_warn (_("A different %s was already specified, is now %s"),
+            string_ptr == &mips_arch_string ? "-march" : "-mtune",
+            new_value);
+
+  *string_ptr = new_value;
+}
+
 int
 md_parse_option (c, arg)
      int c;
@@ -9657,135 +10014,81 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_MIPS1:
-      mips_opts.isa = ISA_MIPS1;
+      file_mips_isa = ISA_MIPS1;
       break;
 
     case OPTION_MIPS2:
-      mips_opts.isa = ISA_MIPS2;
+      file_mips_isa = ISA_MIPS2;
       break;
 
     case OPTION_MIPS3:
-      mips_opts.isa = ISA_MIPS3;
+      file_mips_isa = ISA_MIPS3;
       break;
 
     case OPTION_MIPS4:
-      mips_opts.isa = ISA_MIPS4;
+      file_mips_isa = ISA_MIPS4;
       break;
 
     case OPTION_MIPS5:
-      mips_opts.isa = ISA_MIPS5;
+      file_mips_isa = ISA_MIPS5;
       break;
 
     case OPTION_MIPS32:
-      mips_opts.isa = ISA_MIPS32;
+      file_mips_isa = ISA_MIPS32;
       break;
 
     case OPTION_MIPS64:
-      mips_opts.isa = ISA_MIPS64;
+      file_mips_isa = ISA_MIPS64;
       break;
 
     case OPTION_MTUNE:
-    case OPTION_MARCH:
-    case OPTION_MCPU:
-      {
-       int cpu = CPU_UNKNOWN;
-
-       /* Identify the processor type.  */
-       if (strcasecmp (arg, "default") != 0)
-         {
-           const struct mips_cpu_info *ci;
-
-           ci = mips_cpu_info_from_name (arg);
-           if (ci == NULL || ci->is_isa)
-             {
-               switch (c)
-                 {
-                 case OPTION_MTUNE:
-                   as_fatal (_("invalid architecture -mtune=%s"), arg);
-                   break;
-                 case OPTION_MARCH:
-                   as_fatal (_("invalid architecture -march=%s"), arg);
-                   break;
-                 case OPTION_MCPU:
-                   as_fatal (_("invalid architecture -mcpu=%s"), arg);
-                   break;
-                 }
-             }
-           else
-               cpu = ci->cpu;
-         }
+      mips_set_option_string (&mips_tune_string, arg);
+      break;
 
-       switch (c)
-         {
-         case OPTION_MTUNE:
-           if (mips_tune != CPU_UNKNOWN && mips_tune != cpu)
-             as_warn(_("A different -mtune= was already specified, is now "
-                       "-mtune=%s"), arg);
-           mips_tune = cpu;
-           break;
-         case OPTION_MARCH:
-           if (mips_arch != CPU_UNKNOWN && mips_arch != cpu)
-             as_warn(_("A different -march= was already specified, is now "
-                       "-march=%s"), arg);
-           mips_arch = cpu;
-           break;
-         case OPTION_MCPU:
-           if (mips_cpu != CPU_UNKNOWN && mips_cpu != cpu)
-             as_warn(_("A different -mcpu= was already specified, is now "
-                       "-mcpu=%s"), arg);
-           mips_cpu = cpu;
-         }
-      }
+    case OPTION_MARCH:
+      mips_set_option_string (&mips_arch_string, arg);
       break;
 
     case OPTION_M4650:
-      if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R4650)
-         || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R4650))
-        as_warn(_("A different -march= or -mtune= was already specified, "
-                 "is now -m4650"));
-      mips_arch = CPU_R4650;
-      mips_tune = CPU_R4650;
+      mips_set_option_string (&mips_arch_string, "4650");
+      mips_set_option_string (&mips_tune_string, "4650");
       break;
 
     case OPTION_NO_M4650:
       break;
 
     case OPTION_M4010:
-      if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R4010)
-         || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R4010))
-        as_warn(_("A different -march= or -mtune= was already specified, "
-                 "is now -m4010"));
-      mips_arch = CPU_R4010;
-      mips_tune = CPU_R4010;
+      mips_set_option_string (&mips_arch_string, "4010");
+      mips_set_option_string (&mips_tune_string, "4010");
       break;
 
     case OPTION_NO_M4010:
       break;
 
     case OPTION_M4100:
-      if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_VR4100)
-         || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_VR4100))
-        as_warn(_("A different -march= or -mtune= was already specified, "
-                 "is now -m4100"));
-      mips_arch = CPU_VR4100;
-      mips_tune = CPU_VR4100;
+      mips_set_option_string (&mips_arch_string, "4100");
+      mips_set_option_string (&mips_tune_string, "4100");
       break;
 
     case OPTION_NO_M4100:
       break;
 
     case OPTION_M3900:
-      if ((mips_arch != CPU_UNKNOWN && mips_arch != CPU_R3900)
-         || (mips_tune != CPU_UNKNOWN && mips_tune != CPU_R3900))
-        as_warn(_("A different -march= or -mtune= was already specified, "
-                 "is now -m3900"));
-      mips_arch = CPU_R3900;
-      mips_tune = CPU_R3900;
+      mips_set_option_string (&mips_arch_string, "3900");
+      mips_set_option_string (&mips_tune_string, "3900");
       break;
 
     case OPTION_NO_M3900:
       break;
 
+    case OPTION_MDMX:
+      mips_opts.ase_mdmx = 1;
+      break;
+
+    case OPTION_NO_MDMX:
+      mips_opts.ase_mdmx = 0;
+      break;
+
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
       mips_no_prev_insn (false);
@@ -9796,6 +10099,14 @@ md_parse_option (c, arg)
       mips_no_prev_insn (false);
       break;
 
+    case OPTION_MIPS3D:
+      mips_opts.ase_mips3d = 1;
+      break;
+
+    case OPTION_NO_MIPS3D:
+      mips_opts.ase_mips3d = 0;
+      break;
+
     case OPTION_MEMBEDDED_PIC:
       mips_pic = EMBEDDED_PIC;
       if (USE_GLOBAL_POINTER_OPT && g_switch_seen)
@@ -9859,18 +10170,33 @@ md_parse_option (c, arg)
       break;
 
 #ifdef OBJ_ELF
-      /* The -32 and -64 options tell the assembler to output the 32
-         bit or the 64 bit MIPS ELF format.  */
+      /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
+        and -mabi=64.  */
     case OPTION_32:
-      mips_opts.abi = O32_ABI;
-      break;
-
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-32 is supported for ELF format only"));
+         return 0;
+       }
+      mips_abi = O32_ABI;
+      break;
+
     case OPTION_N32:
-      mips_opts.abi = N32_ABI;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-n32 is supported for ELF format only"));
+         return 0;
+       }
+      mips_abi = N32_ABI;
       break;
 
     case OPTION_64:
-      mips_opts.abi = N64_ABI;
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-64 is supported for ELF format only"));
+         return 0;
+       }
+      mips_abi = N64_ABI;
       if (! support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
@@ -9878,41 +10204,47 @@ md_parse_option (c, arg)
 
     case OPTION_GP32:
       file_mips_gp32 = 1;
-      if (mips_opts.abi != O32_ABI)
-       mips_opts.abi = NO_ABI;
       break;
 
     case OPTION_GP64:
       file_mips_gp32 = 0;
-      if (mips_opts.abi == O32_ABI)
-       mips_opts.abi = NO_ABI;
       break;
 
     case OPTION_FP32:
       file_mips_fp32 = 1;
-      if (mips_opts.abi != O32_ABI)
-       mips_opts.abi = NO_ABI;
+      break;
+
+    case OPTION_FP64:
+      file_mips_fp32 = 0;
       break;
 
 #ifdef OBJ_ELF
     case OPTION_MABI:
+      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+       {
+         as_bad (_("-mabi is supported for ELF format only"));
+         return 0;
+       }
       if (strcmp (arg, "32") == 0)
-       mips_opts.abi = O32_ABI;
+       mips_abi = O32_ABI;
       else if (strcmp (arg, "o64") == 0)
-       mips_opts.abi = O64_ABI;
+       mips_abi = O64_ABI;
       else if (strcmp (arg, "n32") == 0)
-       mips_opts.abi = N32_ABI;
+       mips_abi = N32_ABI;
       else if (strcmp (arg, "64") == 0)
        {
-         mips_opts.abi = N64_ABI;
+         mips_abi = N64_ABI;
          if (! support_64bit_objects())
            as_fatal (_("No compiled in support for 64 bit object file "
                        "format"));
        }
       else if (strcmp (arg, "eabi") == 0)
-       mips_opts.abi = EABI_ABI;
+       mips_abi = EABI_ABI;
       else
-       mips_opts.abi = NO_ABI;
+       {
+         as_fatal (_("invalid abi -mabi=%s"), arg);
+         return 0;
+       }
       break;
 #endif /* OBJ_ELF */
 
@@ -9920,131 +10252,179 @@ md_parse_option (c, arg)
       mips_7000_hilo_fix = true;
       break;
 
-    case OPTION_NO_M7000_HILO_FIX:
+    case OPTION_MNO_7000_HILO_FIX:
       mips_7000_hilo_fix = false;
       break;
 
+#ifdef OBJ_ELF
+    case OPTION_MDEBUG:
+      mips_flag_mdebug = true;
+      break;
+
+    case OPTION_NO_MDEBUG:
+      mips_flag_mdebug = false;
+      break;
+#endif /* OBJ_ELF */
+
     default:
       return 0;
     }
 
   return 1;
 }
+\f
+/* Set up globals to generate code for the ISA or processor
+   described by INFO.  */
 
 static void
-show (stream, string, col_p, first_p)
-     FILE *stream;
-     char *string;
-     int *col_p;
-     int *first_p;
+mips_set_architecture (info)
+     const struct mips_cpu_info *info;
 {
-  if (*first_p)
+  if (info != 0)
     {
-      fprintf (stream, "%24s", "");
-      *col_p = 24;
+      mips_arch_info = info;
+      mips_arch = info->cpu;
+      mips_opts.isa = info->isa;
     }
-  else
+}
+
+
+/* Likewise for tuning.  */
+
+static void
+mips_set_tune (info)
+     const struct mips_cpu_info *info;
+{
+  if (info != 0)
     {
-      fprintf (stream, ", ");
-      *col_p += 2;
+      mips_tune_info = info;
+      mips_tune = info->cpu;
     }
+}
 
-  if (*col_p + strlen (string) > 72)
+
+void
+mips_after_parse_args ()
+{
+  /* GP relative stuff not working for PE */
+  if (strncmp (TARGET_OS, "pe", 2) == 0
+      && g_switch_value != 0)
     {
-      fprintf (stream, "\n%24s", "");
-      *col_p = 24;
+      if (g_switch_seen)
+       as_bad (_("-G not supported in this configuration."));
+      g_switch_value = 0;
     }
 
-  fprintf (stream, "%s", string);
-  *col_p += strlen (string);
+  /* The following code determines the architecture and register size.
+     Similar code was added to GCC 3.3 (see override_options() in
+     config/mips/mips.c).  The GAS and GCC code should be kept in sync
+     as much as possible.  */
 
-  *first_p = 0;
-}
+  if (mips_arch_string != 0)
+    mips_set_architecture (mips_parse_cpu ("-march", mips_arch_string));
 
-void
-md_show_usage (stream)
-     FILE *stream;
-{
-  int column, first;
+  if (mips_tune_string != 0)
+    mips_set_tune (mips_parse_cpu ("-mtune", mips_tune_string));
 
-  fprintf (stream, _("\
-MIPS options:\n\
--membedded-pic         generate embedded position independent code\n\
--EB                    generate big endian output\n\
--EL                    generate little endian output\n\
--g, -g2                        do not remove unneeded NOPs or swap branches\n\
--G NUM                 allow referencing objects up to NUM bytes\n\
-                       implicitly with the gp register [default 8]\n"));
-  fprintf (stream, _("\
--mips1                 generate MIPS ISA I instructions\n\
--mips2                 generate MIPS ISA II instructions\n\
--mips3                 generate MIPS ISA III instructions\n\
--mips4                 generate MIPS ISA IV instructions\n\
--mips5                  generate MIPS ISA V instructions\n\
--mips32                 generate MIPS32 ISA instructions\n\
--mips64                 generate MIPS64 ISA instructions\n\
--march=CPU/-mtune=CPU  generate code/schedule for CPU, where CPU is one of:\n"));
+  if (file_mips_isa != ISA_UNKNOWN)
+    {
+      /* Handle -mipsN.  At this point, file_mips_isa contains the
+        ISA level specified by -mipsN, while mips_opts.isa contains
+        the -march selection (if any).  */
+      if (mips_arch_info != 0)
+       {
+         /* -march takes precedence over -mipsN, since it is more descriptive.
+            There's no harm in specifying both as long as the ISA levels
+            are the same.  */
+         if (file_mips_isa != mips_opts.isa)
+           as_bad (_("-%s conflicts with the other architecture options, which imply -%s"),
+                   mips_cpu_info_from_isa (file_mips_isa)->name,
+                   mips_cpu_info_from_isa (mips_opts.isa)->name);
+       }
+      else
+       mips_set_architecture (mips_cpu_info_from_isa (file_mips_isa));
+    }
 
-  first = 1;
+  if (mips_arch_info == 0)
+    mips_set_architecture (mips_parse_cpu ("default CPU",
+                                          MIPS_CPU_STRING_DEFAULT));
 
-  show (stream, "2000", &column, &first);
-  show (stream, "3000", &column, &first);
-  show (stream, "3900", &column, &first);
-  show (stream, "4000", &column, &first);
-  show (stream, "4010", &column, &first);
-  show (stream, "4100", &column, &first);
-  show (stream, "4111", &column, &first);
-  show (stream, "4300", &column, &first);
-  show (stream, "4400", &column, &first);
-  show (stream, "4600", &column, &first);
-  show (stream, "4650", &column, &first);
-  show (stream, "5000", &column, &first);
-  show (stream, "5200", &column, &first);
-  show (stream, "5230", &column, &first);
-  show (stream, "5231", &column, &first);
-  show (stream, "5261", &column, &first);
-  show (stream, "5721", &column, &first);
-  show (stream, "6000", &column, &first);
-  show (stream, "8000", &column, &first);
-  show (stream, "10000", &column, &first);
-  show (stream, "12000", &column, &first);
-  show (stream, "sb1", &column, &first);
-  fputc ('\n', stream);
+  if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (mips_opts.isa))
+    as_bad ("-march=%s is not compatible with the selected ABI",
+           mips_arch_info->name);
 
-  fprintf (stream, _("\
--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"));
+  /* Optimize for mips_arch, unless -mtune selects a different processor.  */
+  if (mips_tune_info == 0)
+    mips_set_tune (mips_arch_info);
 
-  first = 1;
+  if (file_mips_gp32 >= 0)
+    {
+      /* The user specified the size of the integer registers.  Make sure
+        it agrees with the ABI and ISA.  */
+      if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
+       as_bad (_("-mgp64 used with a 32-bit processor"));
+      else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
+       as_bad (_("-mgp32 used with a 64-bit ABI"));
+      else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
+       as_bad (_("-mgp64 used with a 32-bit ABI"));
+    }
+  else
+    {
+      /* Infer the integer register size from the ABI and processor.
+        Restrict ourselves to 32-bit registers if that's all the
+        processor has, or if the ABI cannot handle 64-bit registers.  */
+      file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
+                       || !ISA_HAS_64BIT_REGS (mips_opts.isa));
+    }
 
-  show (stream, "3900", &column, &first);
-  show (stream, "4010", &column, &first);
-  show (stream, "4100", &column, &first);
-  show (stream, "4650", &column, &first);
-  fputc ('\n', stream);
+  /* ??? GAS treats single-float processors as though they had 64-bit
+     float registers (although it complains when double-precision
+     instructions are used).  As things stand, saying they have 32-bit
+     registers would lead to spurious "register must be even" messages.
+     So here we assume float registers are always the same size as
+     integer ones, unless the user says otherwise.  */
+  if (file_mips_fp32 < 0)
+    file_mips_fp32 = file_mips_gp32;
 
-  fprintf (stream, _("\
--mips16                        generate mips16 instructions\n\
--no-mips16             do not generate mips16 instructions\n"));
-  fprintf (stream, _("\
--mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
--mfp32                 use 32-bit FPRs, regardless of the chosen ISA\n\
--O0                    remove unneeded NOPs, do not swap branches\n\
--O                     remove unneeded NOPs and swap branches\n\
--n                     warn about NOPs generated from macros\n\
---[no-]construct-floats [dis]allow floating point values to be constructed\n\
---trap, --no-break     trap exception on div by 0 and mult overflow\n\
---break, --no-trap     break exception on div by 0 and mult overflow\n"));
-#ifdef OBJ_ELF
-  fprintf (stream, _("\
--KPIC, -call_shared    generate SVR4 position independent code\n\
--non_shared            do not generate position independent code\n\
--xgot                  assume a 32 bit GOT\n\
--32                    create o32 ABI object file (default)\n\
--n32                   create n32 ABI object file\n\
--64                    create 64 ABI object file\n"));
-#endif
+  /* End of GCC-shared inference code.  */
+
+  /* ??? When do we want this flag to be set?   Who uses it?  */
+  if (file_mips_gp32 == 1
+      && mips_abi == NO_ABI
+      && ISA_HAS_64BIT_REGS (mips_opts.isa))
+    mips_32bitmode = 1;
+
+  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
+    as_bad (_("trap exception not supported at ISA 1"));
+
+  /* If the selected architecture includes support for ASEs, enable
+     generation of code for them.  */
+  if (mips_opts.mips16 == -1)
+    mips_opts.mips16 = (CPU_HAS_MIPS16 (mips_arch)) ? 1 : 0;
+  if (mips_opts.ase_mips3d == -1)
+    mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (mips_arch)) ? 1 : 0;
+  if (mips_opts.ase_mdmx == -1)
+    mips_opts.ase_mdmx = (CPU_HAS_MDMX (mips_arch)) ? 1 : 0;
+
+  file_mips_isa = mips_opts.isa;
+  file_ase_mips16 = mips_opts.mips16;
+  file_ase_mips3d = mips_opts.ase_mips3d;
+  file_ase_mdmx = mips_opts.ase_mdmx;
+  mips_opts.gp32 = file_mips_gp32;
+  mips_opts.fp32 = file_mips_fp32;
+
+  if (HAVE_NEWABI)
+    mips_big_got = 1;
+
+  if (mips_flag_mdebug < 0)
+    {
+#ifdef OBJ_MAYBE_ECOFF
+      if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour)
+       mips_flag_mdebug = 1;
+      else
+#endif /* OBJ_MAYBE_ECOFF */
+       mips_flag_mdebug = 0;
+    }
 }
 \f
 void
@@ -10071,7 +10451,7 @@ md_pcrel_from (fixP)
        return 1;
     }
 
-  /* return the address of the delay slot */
+  /* Return the address of the delay slot.  */
   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
 }
 
@@ -10094,7 +10474,7 @@ mips_frob_file_before_adjust ()
 }
 
 /* Sort any unmatched HI16_S relocs so that they immediately precede
-   the corresponding LO reloc.  This is called before md_apply_fix and
+   the corresponding LO reloc.  This is called before md_apply_fix3 and
    tc_gen_reloc.  Unmatched HI16_S relocs can only be generated by
    explicit use of the %hi modifier.  */
 
@@ -10218,14 +10598,42 @@ mips_force_relocation (fixp)
              || fixp->fx_r_type == BFD_RELOC_PCREL_LO16));
 }
 
+#ifdef OBJ_ELF
+static int
+mips_need_elf_addend_fixup (fixP)
+     fixS *fixP;
+{
+  if (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16)
+    return 1;
+  if (mips_pic == EMBEDDED_PIC
+      && S_IS_WEAK (fixP->fx_addsy))
+    return 1;
+  if (mips_pic != EMBEDDED_PIC
+      && (S_IS_WEAK (fixP->fx_addsy)
+         || S_IS_EXTERNAL (fixP->fx_addsy))
+      && !S_IS_COMMON (fixP->fx_addsy))
+    return 1;
+  if (symbol_used_in_reloc_p (fixP->fx_addsy)
+      && (((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)))
+    return 1;
+  return 0;
+}
+#endif
+
 /* Apply a fixup to the object file.  */
 
-int
-md_apply_fix (fixP, valueP)
+void
+md_apply_fix3 (fixP, valP, seg)
      fixS *fixP;
-     valueT *valueP;
+     valueT *valP;
+     segT seg ATTRIBUTE_UNUSED;
 {
-  unsigned char *buf;
+  bfd_byte *buf;
   long insn;
   valueT value;
 
@@ -10247,33 +10655,25 @@ md_apply_fix (fixP, valueP)
          || fixP->fx_r_type == BFD_RELOC_MIPS_REL16
          || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT
          || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);
+         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+         || fixP->fx_r_type == BFD_RELOC_MIPS_JALR);
 
-  value = *valueP;
+  value = *valP;
 
   /* 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)
     {
-      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))))
-
+      if (mips_need_elf_addend_fixup (fixP))
        {
+         reloc_howto_type *howto;
          valueT symval = S_GET_VALUE (fixP->fx_addsy);
+
          value -= symval;
-         if (value != 0
-             && ! fixP->fx_pcrel
-             && fixP->fx_r_type != BFD_RELOC_MIPS_GPREL)
+
+         howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+         if (value != 0 && howto->partial_inplace && ! fixP->fx_pcrel)
            {
              /* In this case, the bfd_install_relocation routine will
                 incorrectly add the symbol value back in.  We just want
@@ -10291,12 +10691,8 @@ md_apply_fix (fixP, valueP)
                     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,
@@ -10337,7 +10733,7 @@ md_apply_fix (fixP, valueP)
     }
 #endif
 
-  fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
+  fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
 
   if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel)
     fixP->fx_done = 1;
@@ -10362,11 +10758,11 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_MIPS_JALR:
     case BFD_RELOC_HI16:
     case BFD_RELOC_HI16_S:
-    case BFD_RELOC_MIPS_GPREL:
+    case BFD_RELOC_GPREL16:
     case BFD_RELOC_MIPS_LITERAL:
     case BFD_RELOC_MIPS_CALL16:
     case BFD_RELOC_MIPS_GOT16:
-    case BFD_RELOC_MIPS_GPREL32:
+    case BFD_RELOC_GPREL32:
     case BFD_RELOC_MIPS_GOT_HI16:
     case BFD_RELOC_MIPS_GOT_LO16:
     case BFD_RELOC_MIPS_CALL_HI16:
@@ -10402,10 +10798,10 @@ md_apply_fix (fixP, valueP)
                    + fixP->fx_next->fx_where);
        }
       value = ((value + 0x8000) >> 16) & 0xffff;
-      buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
+      buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
        buf += 2;
-      md_number_to_chars (buf, value, 2);
+      md_number_to_chars ((char *) buf, value, 2);
       break;
 
     case BFD_RELOC_PCREL_LO16:
@@ -10418,10 +10814,10 @@ md_apply_fix (fixP, valueP)
       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;
+      buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
        buf += 2;
-      md_number_to_chars (buf, value, 2);
+      md_number_to_chars ((char *) buf, value, 2);
       break;
 
     case BFD_RELOC_64:
@@ -10483,10 +10879,10 @@ md_apply_fix (fixP, valueP)
          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;
+         buf = (bfd_byte *) fixP->fx_frag->fr_literal + fixP->fx_where;
          if (target_big_endian)
            buf += 2;
-         md_number_to_chars (buf, value, 2);
+         md_number_to_chars ((char *) buf, value, 2);
        }
       break;
 
@@ -10508,13 +10904,16 @@ md_apply_fix (fixP, valueP)
       /* 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)
+      if (!fixP->fx_done
+         && (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2
+             || fixP->fx_addsy == NULL                 /* ??? */
+             || ! S_IS_DEFINED (fixP->fx_addsy)))
        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);
+      buf = (bfd_byte *) (fixP->fx_where + fixP->fx_frag->fr_literal);
       if (target_big_endian)
        insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
       else
@@ -10577,8 +10976,6 @@ md_apply_fix (fixP, valueP)
     default:
       internalError ();
     }
-
-  return 1;
 }
 
 #if 0
@@ -10736,7 +11133,7 @@ s_align (x)
     }
   if (*input_line_pointer == ',')
     {
-      input_line_pointer++;
+      ++input_line_pointer;
       temp_fill = get_absolute_expression ();
     }
   else
@@ -11001,7 +11398,7 @@ s_mipsset (x)
   char *name = input_line_pointer, ch;
 
   while (!is_end_of_line[(unsigned char) *input_line_pointer])
-    input_line_pointer++;
+    ++input_line_pointer;
   ch = *input_line_pointer;
   *input_line_pointer = '\0';
 
@@ -11064,6 +11461,14 @@ s_mipsset (x)
   else if (strcmp (name, "nomips16") == 0
           || strcmp (name, "noMIPS-16") == 0)
     mips_opts.mips16 = 0;
+  else if (strcmp (name, "mips3d") == 0)
+    mips_opts.ase_mips3d = 1;
+  else if (strcmp (name, "nomips3d") == 0)
+    mips_opts.ase_mips3d = 0;
+  else if (strcmp (name, "mdmx") == 0)
+    mips_opts.ase_mdmx = 1;
+  else if (strcmp (name, "nomdmx") == 0)
+    mips_opts.ase_mdmx = 0;
   else if (strncmp (name, "mips", 4) == 0)
     {
       int isa;
@@ -11072,45 +11477,41 @@ s_mipsset (x)
         say, misuse can cause serious problems.  */
       isa = atoi (name + 4);
       switch (isa)
-      {
-      case  0:
-       mips_opts.gp32 = file_mips_gp32;
-       mips_opts.fp32 = file_mips_fp32;
-       mips_opts.abi = file_mips_abi;
-       break;
-      case  1:
-      case  2:
-      case 32:
-       mips_opts.gp32 = 1;
-       mips_opts.fp32 = 1;
-       break;
-      case  3:
-      case  4:
-      case  5:
-      case 64:
-       /* Loosen ABI register width restriction.  */
-       if (mips_opts.abi == O32_ABI)
-         mips_opts.abi = NO_ABI;
-       mips_opts.gp32 = 0;
-       mips_opts.fp32 = 0;
-       break;
-      default:
-       as_bad (_("unknown ISA level %s"), name + 4);
-       break;
-      }
+       {
+       case  0:
+         mips_opts.gp32 = file_mips_gp32;
+         mips_opts.fp32 = file_mips_fp32;
+         break;
+       case  1:
+       case  2:
+       case 32:
+         mips_opts.gp32 = 1;
+         mips_opts.fp32 = 1;
+         break;
+       case  3:
+       case  4:
+       case  5:
+       case 64:
+         mips_opts.gp32 = 0;
+         mips_opts.fp32 = 0;
+         break;
+       default:
+         as_bad (_("unknown ISA level %s"), name + 4);
+         break;
+       }
 
       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 %s"), name + 4); break;
-      }
+       {
+       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 %s"), name + 4); break;
+       }
     }
   else if (strcmp (name, "autoextend") == 0)
     mips_opts.noautoextend = 0;
@@ -11216,12 +11617,12 @@ s_cpload (ignore)
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
   symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
-  macro_build_lui (NULL, &icnt, &ex, GP);
-  macro_build ((char *) NULL, &icnt, &ex, "addiu", "t,r,j", GP, GP,
-              (int) BFD_RELOC_LO16);
+  macro_build_lui (NULL, &icnt, &ex, mips_gp_register);
+  macro_build ((char *) NULL, &icnt, &ex, "addiu", "t,r,j",
+              mips_gp_register, mips_gp_register, (int) BFD_RELOC_LO16);
 
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "addu", "d,v,t",
-              GP, GP, tc_get_register (0));
+              mips_gp_register, mips_gp_register, tc_get_register (0));
 
   demand_empty_rest_of_line ();
 }
@@ -11231,16 +11632,16 @@ s_cpload (ignore)
 
    If offset is given, this results in:
      sd                $gp, offset($sp)
-     lui       $gp, %gp_rel(%neg(%hi(label)))
-     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
-     addu      $gp, $gp, $reg1
+     lui       $gp, %hi(%neg(%gp_rel(label)))
+     addiu     $gp, $gp, %lo(%neg(%gp_rel(label)))
+     daddu     $gp, $gp, $reg1
 
    If $reg2 is given, this results in:
      daddu     $reg2, $gp, $0
-     lui       $gp, %gp_rel(%neg(%hi(label)))
-     daddiu    $gp, $gp, %gp_rel(%neg(%lo(label)))
-     addu      $gp, $gp, $reg1
- */
+     lui       $gp, %hi(%neg(%gp_rel(label)))
+     addiu     $gp, $gp, %lo(%neg(%gp_rel(label)))
+     daddu     $gp, $gp, $reg1
  $reg1 is normally $25 == $t9.  */
 static void
 s_cpsetup (ignore)
      int ignore ATTRIBUTE_UNUSED;
@@ -11249,9 +11650,9 @@ s_cpsetup (ignore)
   expressionS ex_sym;
   int reg1;
   int icnt = 0;
-  char *sym;
+  char *f;
 
-  /* If we are not generating SVR4 PIC code, .cpload is ignored.
+  /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
      We also need NewABI support.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
     {
@@ -11267,12 +11668,18 @@ s_cpsetup (ignore)
       return;
     }
   else
-    input_line_pointer++;
+    ++input_line_pointer;
   SKIP_WHITESPACE ();
   if (*input_line_pointer == '$')
-    mips_cpreturn_register = tc_get_register (0);
+    {
+      mips_cpreturn_register = tc_get_register (0);
+      mips_cpreturn_offset = -1;
+    }
   else
-    mips_cpreturn_offset = get_absolute_expression ();
+    {
+      mips_cpreturn_offset = get_absolute_expression ();
+      mips_cpreturn_register = -1;
+    }
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
@@ -11280,17 +11687,9 @@ s_cpsetup (ignore)
       return;
     }
   else
-    input_line_pointer++;
+    ++input_line_pointer;
   SKIP_WHITESPACE ();
-  sym = input_line_pointer;
-  while (ISALNUM (*input_line_pointer))
-    input_line_pointer++;
-  *input_line_pointer = 0;
-
-  ex_sym.X_op = O_symbol;
-  ex_sym.X_add_symbol = symbol_find_or_make (sym);
-  ex_sym.X_op_symbol = NULL;
-  ex_sym.X_add_number = 0;
+  expression (&ex_sym);
 
   if (mips_cpreturn_register == -1)
     {
@@ -11306,20 +11705,28 @@ s_cpsetup (ignore)
     macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
                 "d,v,t", mips_cpreturn_register, mips_gp_register, 0);
 
+  /* Ensure there's room for the next two instructions, so that `f'
+     doesn't end up with an address in the wrong frag.  */
+  frag_grow (8);
+  f = frag_more (0);
   macro_build ((char *) NULL, &icnt, &ex_sym, "lui", "t,u", mips_gp_register,
               (int) BFD_RELOC_GPREL16);
-  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
-          NULL, 0, 0, BFD_RELOC_MIPS_SUB);
-  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
-          NULL, 0, 0, BFD_RELOC_HI16_S);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_HI16_S);
+
+  f = frag_more (0);
   macro_build ((char *) NULL, &icnt, &ex_sym, "addiu", "t,r,j",
               mips_gp_register, mips_gp_register, (int) BFD_RELOC_GPREL16);
-  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
-          NULL, 0, 0, BFD_RELOC_MIPS_SUB);
-  fix_new (frag_now, (char *) prev_insn_fixp - 4 - frag_now->fr_literal, 0,
-          NULL, 0, 0, BFD_RELOC_LO16);
-  macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "daddu",
-              "d,v,t", mips_gp_register, mips_gp_register, reg1);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_LO16);
+
+  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+              HAVE_64BIT_ADDRESSES ? "daddu" : "addu", "d,v,t",
+              mips_gp_register, mips_gp_register, reg1);
 
   demand_empty_rest_of_line ();
 }
@@ -11337,6 +11744,7 @@ s_cplocal (ignore)
     }
 
   mips_gp_register = tc_get_register (0);
+  demand_empty_rest_of_line ();
 }
 
 /* Handle the .cprestore pseudo-op.  This stores $gp into a given
@@ -11351,7 +11759,7 @@ s_cprestore (ignore)
   int icnt = 0;
 
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
-   .cprestore is ignored.  */
+     .cprestore is ignored.  */
   if (mips_pic != SVR4_PIC || HAVE_NEWABI)
     {
       s_ignore (0);
@@ -11359,15 +11767,15 @@ s_cprestore (ignore)
     }
 
   mips_cprestore_offset = get_absolute_expression ();
+  mips_cprestore_valid = 1;
 
   ex.X_op = O_constant;
   ex.X_add_symbol = NULL;
   ex.X_op_symbol = NULL;
   ex.X_add_number = mips_cprestore_offset;
 
-  macro_build ((char *) NULL, &icnt, &ex,
-              HAVE_32BIT_ADDRESSES ? "sw" : "sd",
-              "t,o(b)", GP, (int) BFD_RELOC_LO16, SP);
+  macro_build ((char *) NULL, &icnt, &ex, HAVE_32BIT_ADDRESSES ? "sw" : "sd",
+              "t,o(b)", mips_gp_register, (int) BFD_RELOC_LO16, SP);
 
   demand_empty_rest_of_line ();
 }
@@ -11426,7 +11834,7 @@ s_gpvalue (ignore)
       return;
     }
 
-  mips_cpreturn_offset = get_absolute_expression ();
+  mips_gprel_offset = get_absolute_expression ();
 
   demand_empty_rest_of_line ();
 }
@@ -11465,8 +11873,8 @@ s_gpword (ignore)
 
   p = frag_more (4);
   md_number_to_chars (p, (valueT) 0, 4);
-  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, 0,
-              BFD_RELOC_MIPS_GPREL32);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, false,
+              BFD_RELOC_GPREL32);
 
   demand_empty_rest_of_line ();
 }
@@ -11493,7 +11901,7 @@ s_cpadd (ignore)
   reg = tc_get_register (0);
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
               HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
-              "d,v,t", reg, reg, GP);
+              "d,v,t", reg, reg, mips_gp_register);
 
   demand_empty_rest_of_line ();
 }
@@ -11511,8 +11919,7 @@ static void
 s_insn (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
-  if (mips_opts.mips16)
-    mips16_mark_labels ();
+  mips16_mark_labels ();
 
   demand_empty_rest_of_line ();
 }
@@ -11527,7 +11934,7 @@ static void
 s_mips_stab (type)
      int type;
 {
-  if (type == 'n' && mips_opts.mips16)
+  if (type == 'n')
     mips16_mark_labels ();
 
   s_stab (type);
@@ -11557,7 +11964,7 @@ s_mips_weakext (ignore)
     {
       if (S_IS_DEFINED (symbolP))
        {
-         as_bad ("Ignoring attempt to redefine symbol `%s'.",
+         as_bad ("ignoring attempt to redefine symbol %s",
                  S_GET_NAME (symbolP));
          ignore_rest_of_line ();
          return;
@@ -11573,7 +11980,7 @@ s_mips_weakext (ignore)
       if (exp.X_op != O_symbol)
        {
          as_bad ("bad .weakext directive");
-         ignore_rest_of_line();
+         ignore_rest_of_line ();
          return;
        }
       symbol_set_value_expression (symbolP, &exp);
@@ -11596,7 +12003,7 @@ tc_get_register (frame)
   if (*input_line_pointer++ != '$')
     {
       as_warn (_("expected `$'"));
-      reg = 0;
+      reg = ZERO;
     }
   else if (ISDIGIT (*input_line_pointer))
     {
@@ -11604,28 +12011,65 @@ tc_get_register (frame)
       if (reg < 0 || reg >= 32)
        {
          as_warn (_("Bad register number"));
-         reg = 0;
+         reg = ZERO;
        }
     }
   else
     {
-      if (strncmp (input_line_pointer, "fp", 2) == 0)
-       reg = FP;
+      if (strncmp (input_line_pointer, "ra", 2) == 0)
+       {
+         reg = RA;
+         input_line_pointer += 2;
+       }
+      else if (strncmp (input_line_pointer, "fp", 2) == 0)
+       {
+         reg = FP;
+         input_line_pointer += 2;
+       }
       else if (strncmp (input_line_pointer, "sp", 2) == 0)
-       reg = SP;
+       {
+         reg = SP;
+         input_line_pointer += 2;
+       }
       else if (strncmp (input_line_pointer, "gp", 2) == 0)
-       reg = GP;
+       {
+         reg = GP;
+         input_line_pointer += 2;
+       }
       else if (strncmp (input_line_pointer, "at", 2) == 0)
-       reg = AT;
+       {
+         reg = AT;
+         input_line_pointer += 2;
+       }
+      else if (strncmp (input_line_pointer, "kt0", 3) == 0)
+       {
+         reg = KT0;
+         input_line_pointer += 3;
+       }
+      else if (strncmp (input_line_pointer, "kt1", 3) == 0)
+       {
+         reg = KT1;
+         input_line_pointer += 3;
+       }
+      else if (strncmp (input_line_pointer, "zero", 4) == 0)
+       {
+         reg = ZERO;
+         input_line_pointer += 4;
+       }
       else
        {
          as_warn (_("Unrecognized register name"));
-         reg = 0;
+         reg = ZERO;
+         while (ISALNUM(*input_line_pointer))
+          input_line_pointer++;
        }
-      input_line_pointer += 2;
     }
   if (frame)
-    mips_frame_reg = reg != 0 ? reg : SP;
+    {
+      mips_frame_reg = reg != 0 ? reg : SP;
+      mips_frame_reg_valid = 1;
+      mips_cprestore_valid = 0;
+    }
   return reg;
 }
 
@@ -11668,10 +12112,10 @@ nopic_need_relax (sym, before_relaxing)
       const char *symname;
       int change;
 
-      /* Find out whether this symbol can be referenced off the GP
+      /* Find out whether this symbol can be referenced off the $gp
         register.  It can be if it is smaller than the -G size or if
         it is in the .sdata or .sbss section.  Certain symbols can
-        not be referenced off the GP, although it appears as though
+        not be referenced off the $gp, although it appears as though
         they can.  */
       symname = S_GET_NAME (sym);
       if (symname != (const char *) NULL
@@ -11718,7 +12162,7 @@ nopic_need_relax (sym, before_relaxing)
       return change;
     }
   else
-    /* We are not optimizing for the GP register.  */
+    /* We are not optimizing for the $gp register.  */
     return 1;
 }
 
@@ -11937,18 +12381,9 @@ md_estimate_size_before_relax (fragp, segtype)
   boolean linkonce = false;
 
   if (RELAX_MIPS16_P (fragp->fr_subtype))
-    {
-      if (mips16_extended_frag (fragp, segtype, 0))
-       {
-         fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
-         return 4;
-       }
-      else
-       {
-         fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
-         return 2;
-       }
-    }
+    /* We don't want to modify the EXTENDED bit here; it might get us
+       into infinite loops.  We change it only in mips_relax_frag().  */
+    return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
 
   if (mips_pic == NO_PIC)
     {
@@ -11998,8 +12433,10 @@ md_estimate_size_before_relax (fragp, segtype)
                && !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)))
+               && (OUTPUT_FLAVOR != bfd_target_elf_flavour
+                   || (! S_IS_WEAK (sym)
+                       && (! S_IS_EXTERNAL (sym)
+                           || mips_pic == EMBEDDED_PIC)))
 #endif
                );
     }
@@ -12040,7 +12477,8 @@ mips_fix_adjustable (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)))
+      && mips_pic != EMBEDDED_PIC
+      && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
     return 0;
 #endif
   if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
@@ -12089,32 +12527,43 @@ 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 (symbol_section_p (fixp->fx_addsy))
-       reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+       reloc->addend = fixp->fx_addnumber;
       else
-       reloc->addend = fixp->fx_addnumber + reloc->address;
+       {
+         /* We use a special addend for an internal RELLO reloc.  */
+         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;
+       }
     }
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S)
     {
       assert (fixp->fx_next != NULL
              && fixp->fx_next->fx_r_type == BFD_RELOC_PCREL_LO16);
-      /* We use a special addend for an internal RELHI reloc.  The
-        reloc is relative to the RELLO; adjust the addend
+
+      /* The reloc is relative to the RELLO; adjust the addend
         accordingly.  */
-      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));
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+       reloc->addend = fixp->fx_next->fx_addnumber;
       else
-       reloc->addend = (fixp->fx_addnumber
-                        + fixp->fx_next->fx_frag->fr_address
-                        + fixp->fx_next->fx_where);
+       {
+         /* We use a special addend for an internal RELHI reloc.  */
+         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));
+         else
+           reloc->addend = (fixp->fx_addnumber
+                            + fixp->fx_next->fx_frag->fr_address
+                            + fixp->fx_next->fx_where);
+       }
     }
+  else if (fixp->fx_pcrel == 0 || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    reloc->addend = fixp->fx_addnumber;
   else
     {
       if (OUTPUT_FLAVOR != bfd_target_aout_flavour)
@@ -12128,7 +12577,7 @@ tc_gen_reloc (section, fixp)
   /* If this is a variant frag, we may need to adjust the existing
      reloc and generate a new one.  */
   if (fixp->fx_frag->fr_opcode != NULL
-      && (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL
+      && (fixp->fx_r_type == BFD_RELOC_GPREL16
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
          || fixp->fx_r_type == BFD_RELOC_MIPS_CALL16
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
@@ -12148,8 +12597,8 @@ tc_gen_reloc (section, fixp)
       if (fixp->fx_next != NULL
          && fixp->fx_frag == fixp->fx_next->fx_frag)
        {
-         assert ((fixp->fx_r_type == BFD_RELOC_MIPS_GPREL
-                  && fixp->fx_next->fx_r_type == BFD_RELOC_MIPS_GPREL)
+         assert ((fixp->fx_r_type == BFD_RELOC_GPREL16
+                  && fixp->fx_next->fx_r_type == BFD_RELOC_GPREL16)
                  || (fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16
                      && (fixp->fx_next->fx_r_type
                          == BFD_RELOC_MIPS_GOT_LO16))
@@ -12185,7 +12634,7 @@ tc_gen_reloc (section, fixp)
 
       if (mips_pic == NO_PIC)
        {
-         assert (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL);
+         assert (fixp->fx_r_type == BFD_RELOC_GPREL16);
          fixp->fx_r_type = BFD_RELOC_HI16_S;
        }
       else if (mips_pic == SVR4_PIC)
@@ -12207,9 +12656,9 @@ tc_gen_reloc (section, fixp)
        abort ();
     }
 
-  /* Since MIPS ELF uses Rel instead of Rela, encode the vtable entry
-     to be used in the relocation's section offset.  */
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
+     entry to be used in the relocation's section offset.  */
+  if (! HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     {
       reloc->address = reloc->addend;
       reloc->addend = 0;
@@ -12251,6 +12700,19 @@ tc_gen_reloc (section, fixp)
        }
     }
 
+#ifdef OBJ_ELF
+  /* md_apply_fix3 has a double-subtraction hack to get
+     bfd_install_relocation to behave nicely.  GPREL relocations are
+     handled correctly without this hack, so undo it here.  We can't
+     stop md_apply_fix3 from subtracting twice in the first place since
+     the fake addend is required for variant frags above.  */
+  if (fixp->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && (code == BFD_RELOC_GPREL16 || code == BFD_RELOC_MIPS16_GPREL)
+      && reloc->addend != 0
+      && mips_need_elf_addend_fixup (fixp))
+    reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+#endif
+
   /* 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.  */
@@ -12393,12 +12855,12 @@ md_convert_frag (abfd, asec, fragp)
 
       if (use_extend)
        {
-         md_number_to_chars (buf, 0xf000 | extend, 2);
+         md_number_to_chars ((char *) buf, 0xf000 | extend, 2);
          fragp->fr_fix += 2;
          buf += 2;
        }
 
-      md_number_to_chars (buf, insn, 2);
+      md_number_to_chars ((char *) buf, insn, 2);
       fragp->fr_fix += 2;
       buf += 2;
     }
@@ -12482,7 +12944,7 @@ void
 mips_elf_final_processing ()
 {
   /* Write out the register information.  */
-  if (! HAVE_NEWABI)
+  if (mips_abi != N64_ABI)
     {
       Elf32_RegInfo s;
 
@@ -12521,24 +12983,32 @@ mips_elf_final_processing ()
   if (mips_pic != NO_PIC)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
 
+  /* Set MIPS ELF flags for ASEs.  */
+  if (file_ase_mips16)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
+#if 0 /* XXX FIXME */
+  if (file_ase_mips3d)
+    elf_elfheader (stdoutput)->e_flags |= ???;
+#endif
+  if (file_ase_mdmx)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
+
   /* Set the MIPS ELF ABI flags.  */
-  if (file_mips_abi == NO_ABI)
-    ;
-  else if (file_mips_abi == O32_ABI)
+  if (mips_abi == O32_ABI && USE_E_MIPS_ABI_O32)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
-  else if (file_mips_abi == O64_ABI)
+  else if (mips_abi == O64_ABI)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
-  else if (file_mips_abi == EABI_ABI)
+  else if (mips_abi == EABI_ABI)
     {
-      if (mips_eabi64)
+      if (!file_mips_gp32)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
     }
-  else if (file_mips_abi == N32_ABI)
+  else if (mips_abi == N32_ABI)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
 
-  /* Nothing to do for "64".  */
+  /* Nothing to do for N64_ABI.  */
 
   if (mips_32bitmode)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
@@ -12584,7 +13054,7 @@ mips_handle_align (fragp)
       if (bytes & 1)
        {
          *p++ = 0;
-         fragp->fr_fix += 1;
+         fragp->fr_fix++;
        }
 
       memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
@@ -12619,7 +13089,7 @@ get_number ()
       negative = 1;
     }
   if (!ISDIGIT (*input_line_pointer))
-    as_bad (_("Expected simple number."));
+    as_bad (_("expected simple number"));
   if (input_line_pointer[0] == '0')
     {
       if (input_line_pointer[1] == 'x')
@@ -12647,7 +13117,7 @@ get_number ()
     {
       printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
              *input_line_pointer, *input_line_pointer);
-      as_warn (_("Invalid number"));
+      as_warn (_("invalid number"));
       return -1;
     }
   while (ISDIGIT (*input_line_pointer))
@@ -12659,16 +13129,47 @@ get_number ()
 }
 
 /* The .file directive; just like the usual .file directive, but there
-   is an initial number which is the ECOFF file index.  */
+   is an initial number which is the ECOFF file index.  In the non-ECOFF
+   case .file implies DWARF-2.  */
 
 static void
-s_file (x)
+s_mips_file (x)
      int x ATTRIBUTE_UNUSED;
 {
-  int line;
+  static int first_file_directive = 0;
+
+  if (ECOFF_DEBUGGING)
+    {
+      get_number ();
+      s_app_file (0);
+    }
+  else
+    {
+      char *filename;
+
+      filename = dwarf2_directive_file (0);
+
+      /* Versions of GCC up to 3.1 start files with a ".file"
+        directive even for stabs output.  Make sure that this
+        ".file" is handled.  Note that you need a version of GCC
+         after 3.1 in order to support DWARF-2 on MIPS.  */
+      if (filename != NULL && ! first_file_directive)
+       {
+         (void) new_logical_line (filename, -1);
+         s_app_file_string (filename);
+       }
+      first_file_directive = 1;
+    }
+}
+
+/* The .loc directive, implying DWARF-2.  */
 
-  line = get_number ();
-  s_app_file (0);
+static void
+s_mips_loc (x)
+     int x ATTRIBUTE_UNUSED;
+{
+  if (!ECOFF_DEBUGGING)
+    dwarf2_directive_loc (0);
 }
 
 /* The .end directive.  */
@@ -12680,6 +13181,10 @@ s_mips_end (x)
   symbolS *p;
   int maybe_text;
 
+  /* Following functions need their own .frame and .cprestore directives.  */
+  mips_frame_reg_valid = 0;
+  mips_cprestore_valid = 0;
+
   if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
       p = get_symbol ();
@@ -12715,46 +13220,52 @@ s_mips_end (x)
       assert (S_GET_NAME (p));
       if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->isym)))
        as_warn (_(".end symbol does not match .ent symbol."));
+
+      if (debug_type == DEBUG_STABS)
+       stabs_generate_asm_endfunc (S_GET_NAME (p),
+                                   S_GET_NAME (p));
     }
   else
     as_warn (_(".end directive missing or unknown symbol"));
 
-#ifdef MIPS_STABS_ELF
-  {
-    segT saved_seg = now_seg;
-    subsegT saved_subseg = now_subseg;
-    valueT dot;
-    expressionS exp;
-    char *fragp;
+#ifdef OBJ_ELF
+  /* Generate a .pdr section.  */
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+    {
+      segT saved_seg = now_seg;
+      subsegT saved_subseg = now_subseg;
+      valueT dot;
+      expressionS exp;
+      char *fragp;
 
-    dot = frag_now_fix ();
+      dot = frag_now_fix ();
 
 #ifdef md_flush_pending_output
-    md_flush_pending_output ();
+      md_flush_pending_output ();
 #endif
 
-    assert (pdr_seg);
-    subseg_set (pdr_seg, 0);
+      assert (pdr_seg);
+      subseg_set (pdr_seg, 0);
 
-    /* Write the symbol.  */
-    exp.X_op = O_symbol;
-    exp.X_add_symbol = p;
-    exp.X_add_number = 0;
-    emit_expr (&exp, 4);
+      /* Write the symbol.  */
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = p;
+      exp.X_add_number = 0;
+      emit_expr (&exp, 4);
 
-    fragp = frag_more (7 * 4);
+      fragp = frag_more (7 * 4);
 
-    md_number_to_chars (fragp,      (valueT) cur_proc_ptr->reg_mask, 4);
-    md_number_to_chars (fragp +  4, (valueT) cur_proc_ptr->reg_offset, 4);
-    md_number_to_chars (fragp +  8, (valueT) cur_proc_ptr->fpreg_mask, 4);
-    md_number_to_chars (fragp + 12, (valueT) cur_proc_ptr->fpreg_offset, 4);
-    md_number_to_chars (fragp + 16, (valueT) cur_proc_ptr->frame_offset, 4);
-    md_number_to_chars (fragp + 20, (valueT) cur_proc_ptr->frame_reg, 4);
-    md_number_to_chars (fragp + 24, (valueT) cur_proc_ptr->pc_reg, 4);
+      md_number_to_chars (fragp,      (valueT) cur_proc_ptr->reg_mask, 4);
+      md_number_to_chars (fragp +  4, (valueT) cur_proc_ptr->reg_offset, 4);
+      md_number_to_chars (fragp +  8, (valueT) cur_proc_ptr->fpreg_mask, 4);
+      md_number_to_chars (fragp + 12, (valueT) cur_proc_ptr->fpreg_offset, 4);
+      md_number_to_chars (fragp + 16, (valueT) cur_proc_ptr->frame_offset, 4);
+      md_number_to_chars (fragp + 20, (valueT) cur_proc_ptr->frame_reg, 4);
+      md_number_to_chars (fragp + 24, (valueT) cur_proc_ptr->pc_reg, 4);
 
-    subseg_set (saved_seg, saved_subseg);
-  }
-#endif
+      subseg_set (saved_seg, saved_subseg);
+    }
+#endif /* OBJ_ELF */
 
   cur_proc_ptr = NULL;
 }
@@ -12765,17 +13276,16 @@ static void
 s_mips_ent (aent)
      int aent;
 {
-  int number = 0;
   symbolS *symbolP;
   int maybe_text;
 
   symbolP = get_symbol ();
   if (*input_line_pointer == ',')
-    input_line_pointer++;
+    ++input_line_pointer;
   SKIP_WHITESPACE ();
   if (ISDIGIT (*input_line_pointer)
       || *input_line_pointer == '-')
-    number = get_number ();
+    get_number ();
 
 #ifdef BFD_ASSEMBLER
   if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
@@ -12797,6 +13307,10 @@ s_mips_ent (aent)
 
   if (!aent)
     {
+      /* This function needs its own .frame and .cprestore directives.  */
+      mips_frame_reg_valid = 0;
+      mips_cprestore_valid = 0;
+
       cur_proc_ptr = &cur_proc;
       memset (cur_proc_ptr, '\0', sizeof (procS));
 
@@ -12804,7 +13318,11 @@ s_mips_ent (aent)
 
       symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
 
-      numprocs++;
+      ++numprocs;
+
+      if (debug_type == DEBUG_STABS)
+        stabs_generate_asm_func (S_GET_NAME (symbolP),
+                                S_GET_NAME (symbolP));
     }
 
   demand_empty_rest_of_line ();
@@ -12820,36 +13338,38 @@ static void
 s_mips_frame (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
-#ifdef MIPS_STABS_ELF
+#ifdef OBJ_ELF
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+    {
+      long val;
 
-  long val;
+      if (cur_proc_ptr == (procS *) NULL)
+       {
+         as_warn (_(".frame outside of .ent"));
+         demand_empty_rest_of_line ();
+         return;
+       }
 
-  if (cur_proc_ptr == (procS *) NULL)
-    {
-      as_warn (_(".frame outside of .ent"));
-      demand_empty_rest_of_line ();
-      return;
-    }
+      cur_proc_ptr->frame_reg = tc_get_register (1);
 
-  cur_proc_ptr->frame_reg = tc_get_register (1);
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer++ != ','
+         || get_absolute_expression_and_terminator (&val) != ',')
+       {
+         as_warn (_("Bad .frame directive"));
+         --input_line_pointer;
+         demand_empty_rest_of_line ();
+         return;
+       }
+
+      cur_proc_ptr->frame_offset = val;
+      cur_proc_ptr->pc_reg = tc_get_register (0);
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer++ != ','
-      || get_absolute_expression_and_terminator (&val) != ',')
-    {
-      as_warn (_("Bad .frame directive"));
-      --input_line_pointer;
       demand_empty_rest_of_line ();
-      return;
     }
-
-  cur_proc_ptr->frame_offset = val;
-  cur_proc_ptr->pc_reg = tc_get_register (0);
-
-  demand_empty_rest_of_line ();
-#else
-  s_ignore (ignore);
-#endif /* MIPS_STABS_ELF */
+  else
+#endif /* OBJ_ELF */
+    s_ignore (ignore);
 }
 
 /* The .fmask and .mask directives. If the mdebug section is present
@@ -12862,41 +13382,44 @@ static void
 s_mips_mask (reg_type)
      char reg_type;
 {
-#ifdef MIPS_STABS_ELF
-  long mask, off;
-
-  if (cur_proc_ptr == (procS *) NULL)
+#ifdef OBJ_ELF
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
     {
-      as_warn (_(".mask/.fmask outside of .ent"));
-      demand_empty_rest_of_line ();
-      return;
-    }
+      long mask, off;
 
-  if (get_absolute_expression_and_terminator (&mask) != ',')
-    {
-      as_warn (_("Bad .mask/.fmask directive"));
-      --input_line_pointer;
-      demand_empty_rest_of_line ();
-      return;
-    }
+      if (cur_proc_ptr == (procS *) NULL)
+       {
+         as_warn (_(".mask/.fmask outside of .ent"));
+         demand_empty_rest_of_line ();
+         return;
+       }
+
+      if (get_absolute_expression_and_terminator (&mask) != ',')
+       {
+         as_warn (_("Bad .mask/.fmask directive"));
+         --input_line_pointer;
+         demand_empty_rest_of_line ();
+         return;
+       }
 
-  off = get_absolute_expression ();
+      off = get_absolute_expression ();
 
-  if (reg_type == 'F')
-    {
-      cur_proc_ptr->fpreg_mask = mask;
-      cur_proc_ptr->fpreg_offset = off;
+      if (reg_type == 'F')
+       {
+         cur_proc_ptr->fpreg_mask = mask;
+         cur_proc_ptr->fpreg_offset = off;
+       }
+      else
+       {
+         cur_proc_ptr->reg_mask = mask;
+         cur_proc_ptr->reg_offset = off;
+       }
+
+      demand_empty_rest_of_line ();
     }
   else
-    {
-      cur_proc_ptr->reg_mask = mask;
-      cur_proc_ptr->reg_offset = off;
-    }
-
-  demand_empty_rest_of_line ();
-#else
-  s_ignore (reg_type);
-#endif /* MIPS_STABS_ELF */
+#endif /* OBJ_ELF */
+    s_ignore (reg_type);
 }
 
 /* The .loc directive.  */
@@ -12923,176 +13446,175 @@ s_loc (x)
 }
 #endif
 
-/* CPU name/ISA/number mapping table.
+/* A table describing all the processors gas knows about.  Names are
+   matched in the order listed.
 
-   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.  */
+   To ease comparison, please keep this table in the same order as
+   gcc's mips_cpu_info_table[].  */
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
-  /* MIPS1 ISA */
-  { "MIPS1",          1,      ISA_MIPS1,      CPU_R3000, },
-  { "mips",           1,      ISA_MIPS1,      CPU_R3000, },
+  /* Entries for generic ISAs */
+  { "mips1",          1,      ISA_MIPS1,      CPU_R3000 },
+  { "mips2",          1,      ISA_MIPS2,      CPU_R6000 },
+  { "mips3",          1,      ISA_MIPS3,      CPU_R4000 },
+  { "mips4",          1,      ISA_MIPS4,      CPU_R8000 },
+  { "mips5",          1,      ISA_MIPS5,      CPU_MIPS5 },
+  { "mips32",         1,      ISA_MIPS32,     CPU_MIPS32 },
+  { "mips64",         1,      ISA_MIPS64,     CPU_MIPS64 },
+
+  /* MIPS I */
+  { "r3000",          0,      ISA_MIPS1,      CPU_R3000 },
+  { "r2000",          0,      ISA_MIPS1,      CPU_R3000 },
+  { "r3900",          0,      ISA_MIPS1,      CPU_R3900 },
+
+  /* MIPS II */
+  { "r6000",          0,      ISA_MIPS2,      CPU_R6000 },
+
+  /* MIPS III */
+  { "r4000",          0,      ISA_MIPS3,      CPU_R4000 },
+  { "r4010",          0,      ISA_MIPS2,      CPU_R4010 },
+  { "vr4100",         0,      ISA_MIPS3,      CPU_VR4100 },
+  { "vr4111",         0,      ISA_MIPS3,      CPU_R4111 },
+  { "vr4300",         0,      ISA_MIPS3,      CPU_R4300 },
+  { "r4400",          0,      ISA_MIPS3,      CPU_R4400 },
+  { "r4600",          0,      ISA_MIPS3,      CPU_R4600 },
+  { "orion",          0,      ISA_MIPS3,      CPU_R4600 },
+  { "r4650",          0,      ISA_MIPS3,      CPU_R4650 },
+
+  /* MIPS IV */
+  { "r8000",          0,      ISA_MIPS4,      CPU_R8000 },
+  { "r10000",         0,      ISA_MIPS4,      CPU_R10000 },
+  { "r12000",         0,      ISA_MIPS4,      CPU_R12000 },
+  { "vr5000",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "rm5200",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "rm5230",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "rm5231",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "rm5261",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "rm5721",         0,      ISA_MIPS4,      CPU_R5000 },
+  { "r7000",          0,      ISA_MIPS4,      CPU_R5000 },
+
+  /* MIPS 32 */
+  { "4kc",            0,      ISA_MIPS32,     CPU_MIPS32, },
+  { "4km",            0,      ISA_MIPS32,     CPU_MIPS32 },
+  { "4kp",            0,      ISA_MIPS32,     CPU_MIPS32 },
 
-  /* MIPS2 ISA */
-  { "MIPS2",          1,      ISA_MIPS2,      CPU_R6000, },
+  /* MIPS 64 */
+  { "5kc",            0,      ISA_MIPS64,     CPU_MIPS64 },
+  { "20kc",           0,      ISA_MIPS64,     CPU_MIPS64 },
 
-  /* MIPS3 ISA */
-  { "MIPS3",          1,      ISA_MIPS3,      CPU_R4000, },
+  /* Broadcom SB-1 CPU core */
+  { "sb1",            0,      ISA_MIPS64,     CPU_SB1 },
 
-  /* MIPS4 ISA */
-  { "MIPS4",          1,      ISA_MIPS4,      CPU_R8000, },
+  /* End marker */
+  { NULL, 0, 0, 0 }
+};
 
-  /* MIPS5 ISA */
-  { "MIPS5",          1,      ISA_MIPS5,      CPU_MIPS5, },
-  { "Generic-MIPS5",  0,      ISA_MIPS5,      CPU_MIPS5, },
 
-  /* MIPS32 ISA */
-  { "MIPS32",         1,      ISA_MIPS32,     CPU_MIPS32, },
-  { "mipsisa32",      0,      ISA_MIPS32,     CPU_MIPS32, },
-  { "Generic-MIPS32", 0,      ISA_MIPS32,     CPU_MIPS32, },
-  { "4kc",            0,      ISA_MIPS32,     CPU_MIPS32, },
-  { "4km",            0,      ISA_MIPS32,     CPU_MIPS32, },
-  { "4kp",            0,      ISA_MIPS32,     CPU_MIPS32, },
-
-  /* For historical reasons.  */
-  { "MIPS64",         1,      ISA_MIPS3,      CPU_R4000, },
-
-  /* MIPS64 ISA */
-  { "mipsisa64",      1,      ISA_MIPS64,     CPU_MIPS64, },
-  { "Generic-MIPS64", 0,      ISA_MIPS64,     CPU_MIPS64, },
-  { "5kc",            0,      ISA_MIPS64,     CPU_MIPS64, },
-  { "20kc",           0,      ISA_MIPS64,     CPU_MIPS64, },
-
-  /* R2000 CPU */
-  { "R2000",          0,      ISA_MIPS1,      CPU_R2000, },
-  { "2000",           0,      ISA_MIPS1,      CPU_R2000, },
-  { "2k",             0,      ISA_MIPS1,      CPU_R2000, },
-  { "r2k",            0,      ISA_MIPS1,      CPU_R2000, },
-
-  /* R3000 CPU */
-  { "R3000",          0,      ISA_MIPS1,      CPU_R3000, },
-  { "3000",           0,      ISA_MIPS1,      CPU_R3000, },
-  { "3k",             0,      ISA_MIPS1,      CPU_R3000, },
-  { "r3k",            0,      ISA_MIPS1,      CPU_R3000, },
-
-  /* TX3900 CPU */
-  { "R3900",          0,      ISA_MIPS1,      CPU_R3900, },
-  { "3900",           0,      ISA_MIPS1,      CPU_R3900, },
-  { "mipstx39",       0,      ISA_MIPS1,      CPU_R3900, },
-
-  /* R4000 CPU */
-  { "R4000",          0,      ISA_MIPS3,      CPU_R4000, },
-  { "4000",           0,      ISA_MIPS3,      CPU_R4000, },
-  { "4k",             0,      ISA_MIPS3,      CPU_R4000, },   /* beware */
-  { "r4k",            0,      ISA_MIPS3,      CPU_R4000, },
-
-  /* R4010 CPU */
-  { "R4010",          0,      ISA_MIPS2,      CPU_R4010, },
-  { "4010",           0,      ISA_MIPS2,      CPU_R4010, },
-
-  /* R4400 CPU */
-  { "R4400",          0,      ISA_MIPS3,      CPU_R4400, },
-  { "4400",           0,      ISA_MIPS3,      CPU_R4400, },
-
-  /* R4600 CPU */
-  { "R4600",          0,      ISA_MIPS3,      CPU_R4600, },
-  { "4600",           0,      ISA_MIPS3,      CPU_R4600, },
-  { "mips64orion",    0,      ISA_MIPS3,      CPU_R4600, },
-  { "orion",          0,      ISA_MIPS3,      CPU_R4600, },
-
-  /* R4650 CPU */
-  { "R4650",          0,      ISA_MIPS3,      CPU_R4650, },
-  { "4650",           0,      ISA_MIPS3,      CPU_R4650, },
-
-  /* R6000 CPU */
-  { "R6000",          0,      ISA_MIPS2,      CPU_R6000, },
-  { "6000",           0,      ISA_MIPS2,      CPU_R6000, },
-  { "6k",             0,      ISA_MIPS2,      CPU_R6000, },
-  { "r6k",            0,      ISA_MIPS2,      CPU_R6000, },
-
-  /* R8000 CPU */
-  { "R8000",          0,      ISA_MIPS4,      CPU_R8000, },
-  { "8000",           0,      ISA_MIPS4,      CPU_R8000, },
-  { "8k",             0,      ISA_MIPS4,      CPU_R8000, },
-  { "r8k",            0,      ISA_MIPS4,      CPU_R8000, },
-
-  /* R10000 CPU */
-  { "R10000",         0,      ISA_MIPS4,      CPU_R10000, },
-  { "10000",          0,      ISA_MIPS4,      CPU_R10000, },
-  { "10k",            0,      ISA_MIPS4,      CPU_R10000, },
-  { "r10k",           0,      ISA_MIPS4,      CPU_R10000, },
-
-  /* R12000 CPU */
-  { "R12000",         0,      ISA_MIPS4,      CPU_R12000, },
-  { "12000",          0,      ISA_MIPS4,      CPU_R12000, },
-  { "12k",            0,      ISA_MIPS4,      CPU_R12000, },
-  { "r12k",           0,      ISA_MIPS4,      CPU_R12000, },
-
-  /* VR4100 CPU */
-  { "VR4100",         0,      ISA_MIPS3,      CPU_VR4100, },
-  { "4100",           0,      ISA_MIPS3,      CPU_VR4100, },
-  { "mips64vr4100",   0,      ISA_MIPS3,      CPU_VR4100, },
-  { "r4100",          0,      ISA_MIPS3,      CPU_VR4100, },
-
-  /* VR4111 CPU */
-  { "VR4111",         0,      ISA_MIPS3,      CPU_R4111, },
-  { "4111",           0,      ISA_MIPS3,      CPU_R4111, },
-  { "mips64vr4111",   0,      ISA_MIPS3,      CPU_R4111, },
-  { "r4111",          0,      ISA_MIPS3,      CPU_R4111, },
-
-  /* VR4300 CPU */
-  { "VR4300",         0,      ISA_MIPS3,      CPU_R4300, },
-  { "4300",           0,      ISA_MIPS3,      CPU_R4300, },
-  { "mips64vr4300",   0,      ISA_MIPS3,      CPU_R4300, },
-  { "r4300",          0,      ISA_MIPS3,      CPU_R4300, },
-
-  /* VR5000 CPU */
-  { "VR5000",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "5000",           0,      ISA_MIPS4,      CPU_R5000, },
-  { "5k",             0,      ISA_MIPS4,      CPU_R5000, },
-  { "mips64vr5000",   0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5000",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5200",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "rm5200",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5230",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "rm5230",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5231",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "rm5231",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5261",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "rm5261",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5721",          0,      ISA_MIPS4,      CPU_R5000, },
-  { "rm5721",         0,      ISA_MIPS4,      CPU_R5000, },
-  { "r5k",            0,      ISA_MIPS4,      CPU_R5000, },
-  { "r7000",          0,      ISA_MIPS4,      CPU_R5000, },
-
-  /* Broadcom SB-1 CPU */
-  { "SB-1",           0,      ISA_MIPS64,     CPU_SB1, },
-  { "sb-1250",        0,      ISA_MIPS64,     CPU_SB1, },
-  { "sb1",            0,      ISA_MIPS64,     CPU_SB1, },
-  { "sb1250",         0,      ISA_MIPS64,     CPU_SB1, },
-
-  /* End marker.  */
-  { NULL, 0, 0, 0, },
-};
+/* Return true if GIVEN is the same as CANONICAL, or if it is CANONICAL
+   with a final "000" replaced by "k".  Ignore case.
+
+   Note: this function is shared between GCC and GAS.  */
+
+static boolean
+mips_strict_matching_cpu_name_p (canonical, given)
+     const char *canonical, *given;
+{
+  while (*given != 0 && TOLOWER (*given) == TOLOWER (*canonical))
+    given++, canonical++;
+
+  return ((*given == 0 && *canonical == 0)
+         || (strcmp (canonical, "000") == 0 && strcasecmp (given, "k") == 0));
+}
+
+
+/* Return true if GIVEN matches CANONICAL, where GIVEN is a user-supplied
+   CPU name.  We've traditionally allowed a lot of variation here.
+
+   Note: this function is shared between GCC and GAS.  */
+
+static boolean
+mips_matching_cpu_name_p (canonical, given)
+     const char *canonical, *given;
+{
+  /* First see if the name matches exactly, or with a final "000"
+     turned into "k".  */
+  if (mips_strict_matching_cpu_name_p (canonical, given))
+    return true;
+
+  /* If not, try comparing based on numerical designation alone.
+     See if GIVEN is an unadorned number, or 'r' followed by a number.  */
+  if (TOLOWER (*given) == 'r')
+    given++;
+  if (!ISDIGIT (*given))
+    return false;
+
+  /* Skip over some well-known prefixes in the canonical name,
+     hoping to find a number there too.  */
+  if (TOLOWER (canonical[0]) == 'v' && TOLOWER (canonical[1]) == 'r')
+    canonical += 2;
+  else if (TOLOWER (canonical[0]) == 'r' && TOLOWER (canonical[1]) == 'm')
+    canonical += 2;
+  else if (TOLOWER (canonical[0]) == 'r')
+    canonical += 1;
+
+  return mips_strict_matching_cpu_name_p (canonical, given);
+}
+
+
+/* Parse an option that takes the name of a processor as its argument.
+   OPTION is the name of the option and CPU_STRING is the argument.
+   Return the corresponding processor enumeration if the CPU_STRING is
+   recognized, otherwise report an error and return null.
+
+   A similar function exists in GCC.  */
 
 static const struct mips_cpu_info *
-mips_cpu_info_from_name (name)
-     const char *name;
+mips_parse_cpu (option, cpu_string)
+     const char *option, *cpu_string;
 {
-  int i;
+  const struct mips_cpu_info *p;
 
-  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
-    if (strcasecmp (name, mips_cpu_info_table[i].name) == 0)
-      return (&mips_cpu_info_table[i]);
+  /* 'from-abi' selects the most compatible architecture for the given
+     ABI: MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs.  For the
+     EABIs, we have to decide whether we're using the 32-bit or 64-bit
+     version.  Look first at the -mgp options, if given, otherwise base
+     the choice on MIPS_DEFAULT_64BIT.
 
-  return NULL;
+     Treat NO_ABI like the EABIs.  One reason to do this is that the
+     plain 'mips' and 'mips64' configs have 'from-abi' as their default
+     architecture.  This code picks MIPS I for 'mips' and MIPS III for
+     'mips64', just as we did in the days before 'from-abi'.  */
+  if (strcasecmp (cpu_string, "from-abi") == 0)
+    {
+      if (ABI_NEEDS_32BIT_REGS (mips_abi))
+       return mips_cpu_info_from_isa (ISA_MIPS1);
+
+      if (ABI_NEEDS_64BIT_REGS (mips_abi))
+       return mips_cpu_info_from_isa (ISA_MIPS3);
+
+      if (file_mips_gp32 >= 0)
+       return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
+
+      return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
+                                    ? ISA_MIPS3
+                                    : ISA_MIPS1);
+    }
+
+  /* 'default' has traditionally been a no-op.  Probably not very useful.  */
+  if (strcasecmp (cpu_string, "default") == 0)
+    return 0;
+
+  for (p = mips_cpu_info_table; p->name != 0; p++)
+    if (mips_matching_cpu_name_p (p->name, cpu_string))
+      return p;
+
+  as_bad ("Bad value (%s) for %s", cpu_string, option);
+  return 0;
 }
 
+/* Return the canonical processor information for ISA (a member of the
+   ISA_MIPS* enumeration).  */
+
 static const struct mips_cpu_info *
 mips_cpu_info_from_isa (isa)
      int isa;
@@ -13101,22 +13623,119 @@ mips_cpu_info_from_isa (isa)
 
   for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
     if (mips_cpu_info_table[i].is_isa
-      && isa == mips_cpu_info_table[i].isa)
+       && isa == mips_cpu_info_table[i].isa)
       return (&mips_cpu_info_table[i]);
 
   return NULL;
 }
+\f
+static void
+show (stream, string, col_p, first_p)
+     FILE *stream;
+     const char *string;
+     int *col_p;
+     int *first_p;
+{
+  if (*first_p)
+    {
+      fprintf (stream, "%24s", "");
+      *col_p = 24;
+    }
+  else
+    {
+      fprintf (stream, ", ");
+      *col_p += 2;
+    }
+
+  if (*col_p + strlen (string) > 72)
+    {
+      fprintf (stream, "\n%24s", "");
+      *col_p = 24;
+    }
+
+  fprintf (stream, "%s", string);
+  *col_p += strlen (string);
+
+  *first_p = 0;
+}
 
-static const struct mips_cpu_info *
-mips_cpu_info_from_cpu (cpu)
-     int cpu;
+void
+md_show_usage (stream)
+     FILE *stream;
 {
-  int i;
+  int column, first;
+  size_t i;
+
+  fprintf (stream, _("\
+MIPS options:\n\
+-membedded-pic         generate embedded position independent code\n\
+-EB                    generate big endian output\n\
+-EL                    generate little endian output\n\
+-g, -g2                        do not remove unneeded NOPs or swap branches\n\
+-G NUM                 allow referencing objects up to NUM bytes\n\
+                       implicitly with the gp register [default 8]\n"));
+  fprintf (stream, _("\
+-mips1                 generate MIPS ISA I instructions\n\
+-mips2                 generate MIPS ISA II instructions\n\
+-mips3                 generate MIPS ISA III instructions\n\
+-mips4                 generate MIPS ISA IV instructions\n\
+-mips5                  generate MIPS ISA V instructions\n\
+-mips32                 generate MIPS32 ISA instructions\n\
+-mips64                 generate MIPS64 ISA instructions\n\
+-march=CPU/-mtune=CPU  generate code/schedule for CPU, where CPU is one of:\n"));
+
+  first = 1;
 
   for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
-    if (!mips_cpu_info_table[i].is_isa
-      && cpu == mips_cpu_info_table[i].cpu)
-      return (&mips_cpu_info_table[i]);
+    show (stream, mips_cpu_info_table[i].name, &column, &first);
+  show (stream, "from-abi", &column, &first);
+  fputc ('\n', stream);
 
-  return NULL;
+  fprintf (stream, _("\
+-mCPU                  equivalent to -march=CPU -mtune=CPU. Deprecated.\n\
+-no-mCPU               don't generate code specific to CPU.\n\
+                       For -mCPU and -no-mCPU, CPU must be one of:\n"));
+
+  first = 1;
+
+  show (stream, "3900", &column, &first);
+  show (stream, "4010", &column, &first);
+  show (stream, "4100", &column, &first);
+  show (stream, "4650", &column, &first);
+  fputc ('\n', stream);
+
+  fprintf (stream, _("\
+-mips16                        generate mips16 instructions\n\
+-no-mips16             do not generate mips16 instructions\n"));
+  fprintf (stream, _("\
+-mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
+-mfp32                 use 32-bit FPRs, regardless of the chosen ISA\n\
+-O0                    remove unneeded NOPs, do not swap branches\n\
+-O                     remove unneeded NOPs and swap branches\n\
+-n                     warn about NOPs generated from macros\n\
+--[no-]construct-floats [dis]allow floating point values to be constructed\n\
+--trap, --no-break     trap exception on div by 0 and mult overflow\n\
+--break, --no-trap     break exception on div by 0 and mult overflow\n"));
+#ifdef OBJ_ELF
+  fprintf (stream, _("\
+-KPIC, -call_shared    generate SVR4 position independent code\n\
+-non_shared            do not generate position independent code\n\
+-xgot                  assume a 32 bit GOT\n\
+-mabi=ABI              create ABI conformant object file for:\n"));
+
+  first = 1;
+
+  show (stream, "32", &column, &first);
+  show (stream, "o64", &column, &first);
+  show (stream, "n32", &column, &first);
+  show (stream, "64", &column, &first);
+  show (stream, "eabi", &column, &first);
+
+  fputc ('\n', stream);
+
+  fprintf (stream, _("\
+-32                    create o32 ABI object file (default)\n\
+-n32                   create n32 ABI object file\n\
+-64                    create 64 ABI object file\n"));
+#endif
 }
This page took 0.106343 seconds and 4 git commands to generate.