[ bfd/ChangeLog ]
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index f69be037f74d6ef153e883a7a83718502d7cebea..b501c19986ddfa28398ecbbe658a689b4811acc4 100644 (file)
@@ -77,6 +77,8 @@ 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)
@@ -127,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
@@ -175,9 +177,6 @@ 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.  */
@@ -192,7 +191,7 @@ static int file_mips_fp32 = -1;
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, NO_ABI
+  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -216,18 +215,18 @@ static int file_ase_mips3d;
    command line (e.g., by -march).  */
 static int file_ase_mdmx;
 
-/* The argument of the -mcpu= flag.  Historical for code generation.  */
-static int mips_cpu = CPU_UNKNOWN;
-
 /* The argument of the -march= flag.  The architecture we are assembling.  */
 static int mips_arch = CPU_UNKNOWN;
+static const char *mips_arch_string;
+static const struct mips_cpu_info *mips_arch_info;
 
 /* The argument of the -mtune= flag.  The architecture for which we
    are optimizing.  */
 static int mips_tune = CPU_UNKNOWN;
+static const char *mips_tune_string;
+static const struct mips_cpu_info *mips_tune_info;
 
-/* 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
@@ -244,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                \
@@ -252,22 +260,30 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS64            \
    )
 
+/* Return true if ISA supports 64-bit right rotate (dror et al.)
+   instructions.  */
+#define ISA_HAS_DROR(ISA) (    \
+   0                           \
+   )
+
+/* Return true if ISA supports 32-bit right rotate (ror et al.)
+   instructions.  */
+#define ISA_HAS_ROR(ISA) (     \
+   (ISA) == ISA_MIPS32R2       \
+   )
+
 #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.  */
@@ -280,22 +296,30 @@ 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)
+#define CPU_HAS_MIPS16(cpu)                                            \
+   (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0         \
+    || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 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                 \
+#define CPU_HAS_MDMX(cpu)      (FALSE                 \
                                 )
 
+/* True if CPU has a dror instruction.  */
+#define CPU_HAS_DROR(CPU)      ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
+
+/* True if CPU has a ror instruction.  */
+#define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
+
 /* Whether the processor uses hardware interlocks to protect
    reads from the HI and LO registers, and thus does not
    require nops to be inserted.  */
 
 #define hilo_interlocks (mips_arch == CPU_R4010                       \
+                         || mips_arch == CPU_VR5500                   \
                          || mips_arch == CPU_SB1                      \
                          )
 
@@ -303,12 +327,16 @@ static int mips_32bitmode = 0;
    from the GPRs, and thus does not require nops to be inserted.  */
 #define gpr_interlocks \
   (mips_opts.isa != ISA_MIPS1  \
+   || mips_arch == CPU_VR5400  \
+   || mips_arch == CPU_VR5500  \
    || mips_arch == CPU_R3900)
 
 /* As with other "interlocks" this is used by hardware that has FP
    (co-processor) interlocks.  */
 /* Itbl support may require additional care here.  */
 #define cop_interlocks (mips_arch == CPU_R4300                        \
+                        || mips_arch == CPU_VR5400                    \
+                        || mips_arch == CPU_VR5500                    \
                         || mips_arch == CPU_SB1                       \
                        )
 
@@ -318,26 +346,7 @@ static int mips_32bitmode = 0;
 
 /* MIPS PIC level.  */
 
-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,
-
-  /* Generate PIC code without using a global offset table: the data
-     segment has a maximum size of 64K, all data references are off
-     the $gp register, and all text references are PC relative.  This
-     is used on some embedded systems.  */
-  EMBEDDED_PIC
-};
-
-static enum mips_pic_level mips_pic;
+enum mips_pic_level mips_pic;
 
 /* Warn about all NOPS that the assembler generates.  */
 static int warn_nops = 0;
@@ -564,6 +573,15 @@ static const unsigned int mips16_to_32_reg_map[] =
 {
   16, 17, 2, 3, 4, 5, 6, 7
 };
+
+static int mips_fix_4122_bugs;
+
+/* We don't relax branches by default, since this causes us to expand
+   `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
+   fail to compute the offset before expanding the macro to the most
+   efficient expansion.  */
+
+static int mips_relax_branch;
 \f
 /* Since the MIPS does not have multiple forms of PC relative
    instructions, we do not have to do relaxing as is done on other
@@ -641,6 +659,86 @@ static const unsigned int mips16_to_32_reg_map[] =
 #define RELAX_RELOC3(i) (((i) >> 1) & 1)
 #define RELAX_WARN(i) ((i) & 1)
 
+/* Branch without likely bit.  If label is out of range, we turn:
+
+       beq reg1, reg2, label
+       delay slot
+
+   into
+
+        bne reg1, reg2, 0f
+        nop
+        j label
+     0: delay slot
+
+   with the following opcode replacements:
+
+       beq <-> bne
+       blez <-> bgtz
+       bltz <-> bgez
+       bc1f <-> bc1t
+
+       bltzal <-> bgezal  (with jal label instead of j label)
+
+   Even though keeping the delay slot instruction in the delay slot of
+   the branch would be more efficient, it would be very tricky to do
+   correctly, because we'd have to introduce a variable frag *after*
+   the delay slot instruction, and expand that instead.  Let's do it
+   the easy way for now, even if the branch-not-taken case now costs
+   one additional instruction.  Out-of-range branches are not supposed
+   to be common, anyway.
+
+   Branch likely.  If label is out of range, we turn:
+
+       beql reg1, reg2, label
+       delay slot (annulled if branch not taken)
+
+   into
+
+        beql reg1, reg2, 1f
+        nop
+        beql $0, $0, 2f
+        nop
+     1: j[al] label
+        delay slot (executed only if branch taken)
+     2:
+
+   It would be possible to generate a shorter sequence by losing the
+   likely bit, generating something like:
+
+       bne reg1, reg2, 0f
+       nop
+       j[al] label
+       delay slot (executed only if branch taken)
+     0:
+
+       beql -> bne
+       bnel -> beq
+       blezl -> bgtz
+       bgtzl -> blez
+       bltzl -> bgez
+       bgezl -> bltz
+       bc1fl -> bc1t
+       bc1tl -> bc1f
+
+       bltzall -> bgezal  (with jal label instead of j label)
+       bgezall -> bltzal  (ditto)
+
+
+   but it's not clear that it would actually improve performance.  */
+#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar) \
+  ((relax_substateT) \
+   (0xc0000000 \
+    | ((toofar) ? 1 : 0) \
+    | ((link) ? 2 : 0) \
+    | ((likely) ? 4 : 0) \
+    | ((uncond) ? 8 : 0)))
+#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
+#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
+#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
+#define RELAX_BRANCH_TOOFAR(i) (((i) & 1))
+
 /* For mips16 code, we use an entirely different form of relaxation.
    mips16 supports two versions of most instructions which take
    immediate values: a small one which takes some small value, and a
@@ -668,7 +766,7 @@ static const unsigned int mips16_to_32_reg_map[] =
    | ((ext) ? 0x200 : 0)                                       \
    | ((dslot) ? 0x400 : 0)                                     \
    | ((jal_dslot) ? 0x800 : 0))
-#define RELAX_MIPS16_P(i) (((i) & 0x80000000) != 0)
+#define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
 #define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
 #define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
 #define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
@@ -680,6 +778,17 @@ static const unsigned int mips16_to_32_reg_map[] =
 #define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
 #define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
 #define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
+
+/* 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))
+
+/* Is the given value a sign-extended 16-bit value?  */
+#define IS_SEXT_16BIT_NUM(x)                                           \
+  (((x) &~ (offsetT) 0x7fff) == 0                                      \
+   || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
+
 \f
 /* Prototypes for static functions.  */
 
@@ -692,90 +801,149 @@ static const unsigned int mips16_to_32_reg_map[] =
 
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
-static int insn_uses_reg PARAMS ((struct mips_cl_insn *ip,
-                                 unsigned int reg, enum mips_regclass class));
-static int reg_needs_delay PARAMS ((unsigned int));
-static void mips16_mark_labels PARAMS ((void));
-static void append_insn PARAMS ((char *place,
-                                struct mips_cl_insn * ip,
-                                expressionS * p,
-                                bfd_reloc_code_real_type *r,
-                                boolean));
-static void mips_no_prev_insn PARAMS ((int));
-static void mips_emit_delays PARAMS ((boolean));
+static int insn_uses_reg
+  PARAMS ((struct mips_cl_insn *ip, unsigned int reg,
+          enum mips_regclass class));
+static int reg_needs_delay
+  PARAMS ((unsigned int));
+static void mips16_mark_labels
+  PARAMS ((void));
+static void append_insn
+  PARAMS ((char *place, struct mips_cl_insn * ip, expressionS * p,
+          bfd_reloc_code_real_type *r, bfd_boolean));
+static void mips_no_prev_insn
+  PARAMS ((int));
+static void mips_emit_delays
+  PARAMS ((bfd_boolean));
 #ifdef USE_STDARG
-static void macro_build PARAMS ((char *place, int *counter, expressionS * ep,
-                                const char *name, const char *fmt,
-                                ...));
+static void macro_build
+  PARAMS ((char *place, int *counter, expressionS * ep, const char *name,
+          const char *fmt, ...));
 #else
 static void macro_build ();
 #endif
-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 *));
-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));
+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 macro_build_ldst_constoffset
+  PARAMS ((char *place, int *counter, expressionS * ep, const char *op,
+          int valreg, int breg));
+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 *));
+static void move_register
+  PARAMS ((int *, int, int));
+static void macro
+  PARAMS ((struct mips_cl_insn * ip));
+static void mips16_macro
+  PARAMS ((struct mips_cl_insn * ip));
 #ifdef LOSING_COMPILER
-static void macro2 PARAMS ((struct mips_cl_insn * ip));
+static void macro2
+  PARAMS ((struct mips_cl_insn * ip));
 #endif
-static void mips_ip PARAMS ((char *str, struct mips_cl_insn * ip));
-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 *));
+static void mips_ip
+  PARAMS ((char *str, struct mips_cl_insn * ip));
+static void mips16_ip
+  PARAMS ((char *str, struct mips_cl_insn * ip));
+static void mips16_immed
+  PARAMS ((char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean,
+          bfd_boolean, unsigned long *, bfd_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));
+static int support_64bit_objects
+  PARAMS((void));
 #endif
-static symbolS *get_symbol PARAMS ((void));
-static void mips_align PARAMS ((int to, int fill, symbolS *label));
-static void s_align PARAMS ((int));
-static void s_change_sec PARAMS ((int));
-static void s_cons PARAMS ((int));
-static void s_float_cons PARAMS ((int));
-static void s_mips_globl PARAMS ((int));
-static void s_option PARAMS ((int));
-static void s_mipsset PARAMS ((int));
-static void s_abicalls PARAMS ((int));
-static void s_cpload PARAMS ((int));
-static void s_cpsetup PARAMS ((int));
-static void s_cplocal PARAMS ((int));
-static void s_cprestore PARAMS ((int));
-static void s_cpreturn PARAMS ((int));
-static void s_gpvalue PARAMS ((int));
-static void s_gpword PARAMS ((int));
-static void s_cpadd PARAMS ((int));
-static void s_insn PARAMS ((int));
-static void md_obj_begin PARAMS ((void));
-static void md_obj_end PARAMS ((void));
-static long get_number PARAMS ((void));
-static void s_mips_ent PARAMS ((int));
-static void s_mips_end PARAMS ((int));
-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_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 mips_set_option_string
+  PARAMS ((const char **, const char *));
+static symbolS *get_symbol
+  PARAMS ((void));
+static void mips_align
+  PARAMS ((int to, int fill, symbolS *label));
+static void s_align
+  PARAMS ((int));
+static void s_change_sec
+  PARAMS ((int));
+static void s_change_section
+  PARAMS ((int));
+static void s_cons
+  PARAMS ((int));
+static void s_float_cons
+  PARAMS ((int));
+static void s_mips_globl
+  PARAMS ((int));
+static void s_option
+  PARAMS ((int));
+static void s_mipsset
+  PARAMS ((int));
+static void s_abicalls
+  PARAMS ((int));
+static void s_cpload
+  PARAMS ((int));
+static void s_cpsetup
+  PARAMS ((int));
+static void s_cplocal
+  PARAMS ((int));
+static void s_cprestore
+  PARAMS ((int));
+static void s_cpreturn
+  PARAMS ((int));
+static void s_gpvalue
+  PARAMS ((int));
+static void s_gpword
+  PARAMS ((int));
+static void s_gpdword
+  PARAMS ((int));
+static void s_cpadd
+  PARAMS ((int));
+static void s_insn
+  PARAMS ((int));
+static void md_obj_begin
+  PARAMS ((void));
+static void md_obj_end
+  PARAMS ((void));
+static long get_number
+  PARAMS ((void));
+static void s_mips_ent
+  PARAMS ((int));
+static void s_mips_end
+  PARAMS ((int));
+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_mips_file
+  PARAMS ((int));
+static void s_mips_loc
+  PARAMS ((int));
+static int mips16_extended_frag
+  PARAMS ((fragS *, asection *, long));
+static int relaxed_branch_length (fragS *, asection *, int);
+static int validate_mips_insn
+  PARAMS ((const struct mips_opcode *));
+static void show
+  PARAMS ((FILE *, const char *, int *, int *));
 #ifdef OBJ_ELF
-static int mips_need_elf_addend_fixup PARAMS ((fixS *));
+static int mips_need_elf_addend_fixup
+  PARAMS ((fixS *));
 #endif
 
 /* Return values of my_getSmallExpression().  */
@@ -815,9 +983,18 @@ 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 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));
+static void mips_set_architecture
+  PARAMS ((const struct mips_cpu_info *));
+static void mips_set_tune
+  PARAMS ((const struct mips_cpu_info *));
+static bfd_boolean mips_strict_matching_cpu_name_p
+  PARAMS ((const char *, const char *));
+static bfd_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));
 \f
 /* Pseudo-op table.
 
@@ -853,6 +1030,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpreturn", s_cpreturn, 0},
   {"gpvalue", s_gpvalue, 0},
   {"gpword", s_gpword, 0},
+  {"gpdword", s_gpdword, 0},
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
 
@@ -879,15 +1057,14 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"long", s_cons, 2},
   {"octa", s_cons, 4},
   {"quad", s_cons, 3},
+  {"section", s_change_section, 0},
   {"short", s_cons, 1},
   {"single", s_float_cons, 'f'},
   {"stabn", s_mips_stab, 'n'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
 
-#ifdef MIPS_STABS_ELF
   { "extern", ecoff_directive_extern, 0},
-#endif
 
   { NULL, NULL, 0 },
 };
@@ -961,48 +1138,19 @@ static bfd_reloc_code_real_type offset_reloc[3]
 
 /* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc.  */
 
-static boolean imm_unmatched_hi;
+static bfd_boolean imm_unmatched_hi;
 
 /* These are set by mips16_ip if an explicit extension is used.  */
 
-static boolean mips16_small, mips16_ext;
+static bfd_boolean mips16_small, mips16_ext;
 
-#ifdef MIPS_STABS_ELF
-/* The pdr segment for per procedure frame/regmask info */
+#ifdef OBJ_ELF
+/* 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.  */
 
 const char *
@@ -1018,17 +1166,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 ();
@@ -1134,7 +1291,21 @@ md_begin ()
   symbol_table_insert (symbol_new ("$pc", reg_section, -1,
                                   &zero_address_frag));
 
-  mips_no_prev_insn (false);
+  /* If we don't add these register names to the symbol table, they
+     may end up being added as regular symbols by operand(), and then
+     make it to the object file as undefined in case they're not
+     regarded as local symbols.  They're local in o32, since `$' is a
+     local symbol prefix, but not in n32 or n64.  */
+  for (i = 0; i < 8; i++)
+    {
+      char buf[6];
+
+      sprintf (buf, "$fcc%i", i);
+      symbol_table_insert (symbol_new (buf, reg_section, -1,
+                                      &zero_address_frag));
+    }
+
+  mips_no_prev_insn (FALSE);
 
   mips_gprmask = 0;
   mips_cprmask[0] = 0;
@@ -1178,7 +1349,7 @@ md_begin ()
        if (strcmp (TARGET_OS, "elf") != 0)
          flags |= SEC_ALLOC | SEC_LOAD;
 
-       if (file_mips_abi != N64_ABI)
+       if (mips_abi != N64_ABI)
          {
            sec = subseg_new (".reginfo", (subsegT) 0);
 
@@ -1224,12 +1395,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);
@@ -1256,7 +1430,7 @@ md_assemble (str)
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
   imm_expr.X_op = O_absent;
-  imm_unmatched_hi = false;
+  imm_unmatched_hi = FALSE;
   offset_expr.X_op = O_absent;
   imm_reloc[0] = BFD_RELOC_UNUSED;
   imm_reloc[1] = BFD_RELOC_UNUSED;
@@ -1292,9 +1466,9 @@ md_assemble (str)
       if (imm_expr.X_op != O_absent)
        append_insn (NULL, &insn, &imm_expr, imm_reloc, imm_unmatched_hi);
       else if (offset_expr.X_op != O_absent)
-       append_insn (NULL, &insn, &offset_expr, offset_reloc, false);
+       append_insn (NULL, &insn, &offset_expr, offset_reloc, FALSE);
       else
-       append_insn (NULL, &insn, NULL, unused_reloc, false);
+       append_insn (NULL, &insn, NULL, unused_reloc, FALSE);
     }
 }
 
@@ -1447,7 +1621,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
      struct mips_cl_insn *ip;
      expressionS *address_expr;
      bfd_reloc_code_real_type *reloc_type;
-     boolean unmatched_hi;
+     bfd_boolean unmatched_hi;
 {
   register unsigned long prev_pinfo, pinfo;
   char *f;
@@ -1702,6 +1876,50 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       if (prev_prev_nop && nops == 0)
        ++nops;
 
+      if (mips_fix_4122_bugs && prev_insn.insn_mo->name)
+       {
+         /* We're out of bits in pinfo, so we must resort to string
+            ops here.  Shortcuts are selected based on opcodes being
+            limited to the VR4122 instruction set.  */
+         int min_nops = 0;
+         const char *pn = prev_insn.insn_mo->name;
+         const char *tn = ip->insn_mo->name;
+         if (strncmp(pn, "macc", 4) == 0
+             || strncmp(pn, "dmacc", 5) == 0)
+           {
+             /* Errata 21 - [D]DIV[U] after [D]MACC */
+             if (strstr (tn, "div"))
+               {
+                 min_nops = 1;
+               }
+
+             /* Errata 23 - Continuous DMULT[U]/DMACC instructions */
+             if (pn[0] == 'd' /* dmacc */
+                 && (strncmp(tn, "dmult", 5) == 0
+                     || strncmp(tn, "dmacc", 5) == 0))
+               {
+                 min_nops = 1;
+               }
+
+             /* Errata 24 - MT{LO,HI} after [D]MACC */
+             if (strcmp (tn, "mtlo") == 0
+                 || strcmp (tn, "mthi") == 0)
+               {
+                 min_nops = 1;
+               }
+
+           }
+         else if (strncmp(pn, "dmult", 5) == 0
+                  && (strncmp(tn, "dmult", 5) == 0
+                      || strncmp(tn, "dmacc", 5) == 0))
+           {
+             /* Here is the rest of errata 23.  */
+             min_nops = 1;
+           }
+         if (nops < min_nops)
+           nops = min_nops;
+       }
+
       /* If we are being given a nop instruction, don't bother with
         one of the nops we would otherwise output.  This will only
         happen when a nop instruction is used with mips_optimize set
@@ -1796,7 +2014,35 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
        }
     }
 
-  if (*reloc_type > BFD_RELOC_UNUSED)
+  if (place == NULL
+      && address_expr
+      && *reloc_type == BFD_RELOC_16_PCREL_S2
+      && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
+         || pinfo & INSN_COND_BRANCH_LIKELY)
+      && mips_relax_branch
+      /* Don't try branch relaxation within .set nomacro, or within
+        .set noat if we use $at for PIC computations.  If it turns
+        out that the branch was out-of-range, we'll get an error.  */
+      && !mips_opts.warn_about_macros
+      && !(mips_opts.noat && mips_pic != NO_PIC)
+      && !mips_opts.mips16)
+    {
+      f = frag_var (rs_machine_dependent,
+                   relaxed_branch_length
+                   (NULL, NULL,
+                    (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
+                    : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 : 0), 4,
+                   RELAX_BRANCH_ENCODE
+                   (pinfo & INSN_UNCOND_BRANCH_DELAY,
+                    pinfo & INSN_COND_BRANCH_LIKELY,
+                    pinfo & INSN_WRITE_GPR_31,
+                    0),
+                   address_expr->X_add_symbol,
+                   address_expr->X_add_number,
+                   0);
+      *reloc_type = BFD_RELOC_UNUSED;
+    }
+  else if (*reloc_type > BFD_RELOC_UNUSED)
     {
       /* We need to set up a variant frag.  */
       assert (mips_opts.mips16 && address_expr != NULL);
@@ -1864,6 +2110,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              break;
 
            case BFD_RELOC_LO16:
+           case BFD_RELOC_MIPS_GOT_DISP:
              ip->insn_opcode |= address_expr->X_add_number & 0xffff;
              break;
 
@@ -1871,8 +2118,7 @@ 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)
+             if (address_expr->X_add_number & ~0xfffffff)
                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;
@@ -1882,8 +2128,7 @@ 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)
+             if (address_expr->X_add_number & ~0xfffffff)
                as_bad (_("jump address range overflow (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |=
@@ -1892,10 +2137,6 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 | ((address_expr->X_add_number & 0x3fffc) >> 2));
              break;
 
-           case BFD_RELOC_16_PCREL:
-             ip->insn_opcode |= address_expr->X_add_number & 0xffff;
-             break;
-
            case BFD_RELOC_16_PCREL_S2:
              goto need_reloc;
 
@@ -1911,8 +2152,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
            {
              fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
                                     address_expr,
-                                    (*reloc_type == BFD_RELOC_16_PCREL
-                                     || *reloc_type == BFD_RELOC_16_PCREL_S2),
+                                    *reloc_type == BFD_RELOC_16_PCREL_S2,
                                     reloc_type[0]);
 
              /* These relocations can have an addend that won't fit in
@@ -1958,7 +2198,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  address_expr->X_add_number = 0;
 
                  fixp[1] = fix_new_exp (frag_now, f - frag_now->fr_literal,
-                                        4, address_expr, false,
+                                        4, address_expr, FALSE,
                                         reloc_type[1]);
 
                  /* These relocations can have an addend that won't fit in
@@ -1990,7 +2230,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
                      fixp[2] = fix_new_exp (frag_now,
                                             f - frag_now->fr_literal, 4,
-                                            address_expr, false,
+                                            address_expr, FALSE,
                                             reloc_type[2]);
 
                      /* These relocations can have an addend that won't fit in
@@ -2546,7 +2786,7 @@ mips_no_prev_insn (preserve)
 
 static void
 mips_emit_delays (insns)
-     boolean insns;
+     bfd_boolean insns;
 {
   if (! mips_opts.noreorder)
     {
@@ -2600,6 +2840,20 @@ mips_emit_delays (insns)
            ++nops;
        }
 
+      if (mips_fix_4122_bugs && prev_insn.insn_mo->name)
+       {
+         int min_nops = 0;
+         const char *pn = prev_insn.insn_mo->name;
+         if (strncmp(pn, "macc", 4) == 0
+             || strncmp(pn, "dmacc", 5) == 0
+             || strncmp(pn, "dmult", 5) == 0)
+           {
+             min_nops = 1;
+           }
+         if (nops < min_nops)
+           nops = min_nops;
+       }
+
       if (nops > 0)
        {
          struct insn_label_list *l;
@@ -2722,11 +2976,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 
+      /* 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
+                               | (file_ase_mips16 ? INSN_MIPS16 : 0)),
+                              mips_arch)
          && (mips_arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
        break;
 
@@ -2765,6 +3022,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
 
        case 'd':
        case 'G':
+       case 'K':
          insn.insn_opcode |= va_arg (args, int) << OP_SH_RD;
          continue;
 
@@ -2862,10 +3120,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
              ep = NULL;
            }
          else
-           if (mips_pic == EMBEDDED_PIC)
-             *r = BFD_RELOC_16_PCREL_S2;
-           else
-             *r = BFD_RELOC_16_PCREL;
+           *r = BFD_RELOC_16_PCREL_S2;
          continue;
 
        case 'a':
@@ -2885,7 +3140,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   va_end (args);
   assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
-  append_insn (place, &insn, ep, r, false);
+  append_insn (place, &insn, ep, r, FALSE);
 }
 
 static void
@@ -2914,7 +3169,7 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
     }
 
   insn.insn_opcode = insn.insn_mo->match;
-  insn.use_extend = false;
+  insn.use_extend = FALSE;
 
   for (;;)
     {
@@ -2992,8 +3247,8 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
              *r = (int) BFD_RELOC_UNUSED + c;
            else
              {
-               mips16_immed (NULL, 0, c, ep->X_add_number, false, false,
-                             false, &insn.insn_opcode, &insn.use_extend,
+               mips16_immed (NULL, 0, c, ep->X_add_number, FALSE, FALSE,
+                             FALSE, &insn.insn_opcode, &insn.use_extend,
                              &insn.extend);
                ep = NULL;
                *r = BFD_RELOC_UNUSED;
@@ -3011,7 +3266,7 @@ mips16_macro_build (place, counter, ep, name, fmt, args)
 
   assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
-  append_insn (place, &insn, ep, r, false);
+  append_insn (place, &insn, ep, r, FALSE);
 }
 
 /*
@@ -3023,12 +3278,18 @@ macro_build_jalr (icnt, ep)
      int icnt;
      expressionS *ep;
 {
+  char *f;
+
   if (HAVE_NEWABI)
-    frag_more (0);
+    {
+      frag_grow (4);
+      f = frag_more (0);
+    }
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
               RA, PIC_CALL_REG);
   if (HAVE_NEWABI)
-    fix_new_exp (frag_now, 0, 0, ep, false, BFD_RELOC_MIPS_JALR);
+    fix_new_exp (frag_now, f - frag_now->fr_literal,
+                0, ep, FALSE, BFD_RELOC_MIPS_JALR);
 }
 
 /*
@@ -3045,8 +3306,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);
 
@@ -3065,12 +3326,13 @@ macro_build_lui (place, counter, ep, regnum)
                                >> 16) & 0xffff;
       *r = BFD_RELOC_UNUSED;
     }
-  else if (! HAVE_NEWABI)
+  else
     {
       assert (ep->X_op == O_symbol);
       /* _gp_disp is a special case, used from s_cpload.  */
       assert (mips_pic == NO_PIC
-             || strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0);
+             || (! HAVE_NEWABI
+                 && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0));
       *r = BFD_RELOC_HI16_S;
     }
 
@@ -3094,10 +3356,56 @@ macro_build_lui (place, counter, ep, regnum)
   if (*r == BFD_RELOC_UNUSED)
     {
       insn.insn_opcode |= high_expr.X_add_number;
-      append_insn (place, &insn, NULL, r, false);
+      append_insn (place, &insn, NULL, r, FALSE);
+    }
+  else
+    append_insn (place, &insn, &high_expr, r, FALSE);
+}
+
+/* Generate a sequence of instructions to do a load or store from a constant
+   offset off of a base register (breg) into/from a target register (treg),
+   using AT if necessary.  */
+static void
+macro_build_ldst_constoffset (place, counter, ep, op, treg, breg)
+     char *place;
+     int *counter;
+     expressionS *ep;
+     const char *op;
+     int treg, breg;
+{
+  assert (ep->X_op == O_constant);
+
+  /* Right now, this routine can only handle signed 32-bit contants.  */
+  if (! IS_SEXT_32BIT_NUM(ep->X_add_number))
+    as_warn (_("operand overflow"));
+
+  if (IS_SEXT_16BIT_NUM(ep->X_add_number))
+    {
+      /* Signed 16-bit offset will fit in the op.  Easy!  */
+      macro_build (place, counter, ep, op, "t,o(b)", treg,
+                  (int) BFD_RELOC_LO16, breg);
     }
   else
-    append_insn (place, &insn, &high_expr, r, false);
+    {
+      /* 32-bit offset, need multiple instructions and AT, like:
+          lui      $tempreg,const_hi       (BFD_RELOC_HI16_S)
+          addu     $tempreg,$tempreg,$breg
+           <op>     $treg,const_lo($tempreg)   (BFD_RELOC_LO16)
+         to handle the complete offset.  */
+      macro_build_lui (place, counter, ep, AT);
+      if (place != NULL)
+       place += 4;
+      macro_build (place, counter, (expressionS *) NULL,
+                  HAVE_32BIT_ADDRESSES ? "addu" : "daddu",
+                  "d,v,t", AT, AT, breg);
+      if (place != NULL)
+       place += 4;
+      macro_build (place, counter, ep, op, "t,o(b)", treg,
+                  (int) BFD_RELOC_LO16, AT);
+
+      if (mips_opts.noat)
+       as_warn (_("Macro used $at after \".set noat\""));
+    }
 }
 
 /*                     set_at()
@@ -3214,11 +3522,6 @@ 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.
@@ -3526,9 +3829,9 @@ load_address (counter, reg, ep, 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
+        If $at is already in use, we use a path which is suboptimal
         on superscalar processors.
           lui          $reg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
           daddiu       $reg,<sym>              (BFD_RELOC_MIPS_HIGHER)
@@ -3542,7 +3845,7 @@ load_address (counter, reg, ep, used_at)
          /* 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);
@@ -3554,7 +3857,7 @@ load_address (counter, reg, ep, 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;
            }
@@ -3606,20 +3909,32 @@ load_address (counter, reg, ep, 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_DISP)
         If there is a constant, it must be added in after.  */
       ex.X_add_number = ep->X_add_number;
       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, 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),
-                   ep->X_add_symbol, (offsetT) 0, (char *) NULL);
-      macro_build (p, counter, ep,
-                  HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu",
-                  "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
+      if (HAVE_NEWABI)
+       {
+         macro_build ((char *) NULL, counter, ep,
+                      HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg,
+                      (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+       }
+      else
+       {
+         macro_build ((char *) NULL, counter, ep,
+                      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),
+                       ep->X_add_symbol, (offsetT) 0, (char *) NULL);
+         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)
@@ -3797,7 +4112,7 @@ macro (ip)
         sub v0,$zero,$a0
         */
 
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
 
@@ -4254,20 +4569,20 @@ 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);
          return;
        }
 
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       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);
        }
@@ -4303,7 +4618,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;
@@ -4366,7 +4681,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);
@@ -4416,13 +4731,13 @@ macro (ip)
       s = "ddivu";
       s2 = "mfhi";
     do_divu3:
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       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
@@ -4457,6 +4772,16 @@ macro (ip)
       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;
@@ -4540,9 +4865,9 @@ 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
+           If $at is already in use, we use a path which is suboptimal
            on superscalar processors.
              lui       $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHEST)
              daddiu    $tempreg,<sym>          (BFD_RELOC_MIPS_HIGHER)
@@ -4557,7 +4882,7 @@ macro (ip)
              /* 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);
@@ -4569,8 +4894,8 @@ macro (ip)
                               AT, AT, (int) BFD_RELOC_LO16);
                  macro_build (p, &icnt, (expressionS *) NULL, "dsll32",
                               "d,w,<", tempreg, tempreg, 0);
-                 macro_build (p, &icnt, (expressionS *) NULL, "dadd", "d,v,t",
-                              tempreg, tempreg, AT);
+                 macro_build (p, &icnt, (expressionS *) NULL, "daddu",
+                              "d,v,t", tempreg, tempreg, AT);
                  used_at = 1;
                }
              else
@@ -4641,12 +4966,23 @@ macro (ip)
               addu     $tempreg,$tempreg,$at
             For a local symbol, we want the same instruction
             sequence, but we output a BFD_RELOC_LO16 reloc on the
-            addiu instruction.  */
+            addiu instruction.
+
+            For NewABI, we want for local or external data addresses
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_DISP)
+            For a local function symbol, we want
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
+              nop
+              addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_MIPS_GOT_OFST)
+          */
+
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          frag_grow (32);
          if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
            lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
+         else if (HAVE_NEWABI)
+           lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP;
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
                       "t,o(b)", tempreg, lw_reloc_type, mips_gp_register);
@@ -4746,6 +5082,7 @@ macro (ip)
          char *p;
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
+         int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
 
          /* This is the large GOT case.  If this is a reference to an
             external symbol, and there is no constant, we want
@@ -4787,31 +5124,10 @@ macro (ip)
               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)
+            For NewABI, we want for local data addresses
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_DISP)
           */
-         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);
@@ -4932,12 +5248,21 @@ macro (ip)
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
              p += 4;
            }
+
+         if (HAVE_NEWABI)
+           local_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP;
          macro_build (p, &icnt, &offset_expr,
                       HAVE_32BIT_ADDRESSES ? "lw" : "ld",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16,
+                      "t,o(b)", tempreg,
+                      local_reloc_type,
                       mips_gp_register);
          p += 4;
-         if (expr1.X_add_number >= -0x8000
+         if (expr1.X_add_number == 0 && HAVE_NEWABI)
+           {
+             /* BFD_RELOC_MIPS_GOT_DISP is sufficient for newabi */
+           }
+        else
+          if (expr1.X_add_number >= -0x8000
              && expr1.X_add_number < 0x8000)
            {
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -5059,10 +5384,9 @@ macro (ip)
                      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)",
-                              mips_gp_register, (int) BFD_RELOC_LO16,
-                              mips_frame_reg);
+                 macro_build_ldst_constoffset ((char *) NULL, &icnt, &expr1,
+                                               HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                                               mips_gp_register, mips_frame_reg);
                }
            }
        }
@@ -5192,10 +5516,9 @@ macro (ip)
                    macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                                 "nop", "");
                  expr1.X_add_number = mips_cprestore_offset;
-                 macro_build ((char *) NULL, &icnt, &expr1,
-                              HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)",
-                              mips_gp_register, (int) BFD_RELOC_LO16,
-                              mips_frame_reg);
+                 macro_build_ldst_constoffset ((char *) NULL, &icnt, &expr1,
+                                               HAVE_32BIT_ADDRESSES ? "lw" : "ld",
+                                               mips_gp_register, mips_frame_reg);
                }
            }
        }
@@ -5495,20 +5818,22 @@ macro (ip)
             If we have 64-bit addresses, as an optimization, for
             addresses which are 32-bit constants (e.g. kseg0/kseg1
             addresses) we fall back to the 32-bit address generation
-            mechanism since it is more efficient.  This code should
+            mechanism since it is more efficient.  Note that due to
+            the signed offset used by memory operations, the 32-bit
+            range is shifted down by 32768 here.  This code should
             probably attempt to generate 64-bit constants more
             efficiently in general.
           */
          if (HAVE_64BIT_ADDRESSES
              && !(offset_expr.X_op == O_constant
-                  && IS_SEXT_32BIT_NUM (offset_expr.X_add_number)))
+                  && IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
            {
              p = NULL;
 
              /* We don't do GP optimization for now because RELAX_ENCODE can't
                 hold the data for such large chunks.  */
 
-             if (used_at == 0)
+             if (used_at == 0 && ! mips_opts.noat)
                {
                  macro_build (p, &icnt, &offset_expr, "lui", "t,u",
                               tempreg, (int) BFD_RELOC_MIPS_HIGHEST);
@@ -5606,6 +5931,7 @@ macro (ip)
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
          char *p;
+         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
 
          /* If this is a reference to an external symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
@@ -5616,6 +5942,8 @@ macro (ip)
               nop
               addiu    $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
               <op>     $treg,0($tempreg)
+            If we have NewABI, we want
+              lw       $reg,<sym>($gp)         (BFD_RELOC_MIPS_GOT_DISP)
             If there is a base register, we add it to $tempreg before
             the <op>.  If there is a constant, we stick it in the
             <op> instruction.  We don't handle constants larger than
@@ -5625,13 +5953,15 @@ macro (ip)
          assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
+         if (HAVE_NEWABI)
+           lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
            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, mips_gp_register);
+                      (int) lw_reloc_type, 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),
@@ -6555,7 +6885,7 @@ macro2 (ip)
       dbl = 1;
     case M_MULO:
     do_mulo:
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       if (imm)
@@ -6569,8 +6899,8 @@ macro2 (ip)
       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;
@@ -6595,7 +6925,7 @@ macro2 (ip)
       dbl = 1;
     case M_MULOU:
     do_mulou:
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       if (imm)
@@ -6608,8 +6938,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;
@@ -6623,6 +6953,26 @@ macro2 (ip)
       break;
 
     case M_DROL:
+      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_arch))
+       {
+         if (dreg == sreg)
+           {
+             tempreg = AT;
+             used_at = 1;
+           }
+         else
+           {
+             tempreg = dreg;
+             used_at = 0;
+           }
+         macro_build ((char *) NULL, &icnt, NULL, "dnegu",
+                      "d,w", tempreg, treg);
+         macro_build ((char *) NULL, &icnt, NULL, "drorv",
+                      "d,t,s", dreg, sreg, tempreg);
+         if (used_at)
+           break;
+         return;
+       }
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsubu",
                   "d,v,t", AT, 0, treg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsrlv",
@@ -6634,6 +6984,26 @@ macro2 (ip)
       break;
 
     case M_ROL:
+      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_arch))
+       {
+         if (dreg == sreg)
+           {
+             tempreg = AT;
+             used_at = 1;
+           }
+         else
+           {
+             tempreg = dreg;
+             used_at = 0;
+           }
+         macro_build ((char *) NULL, &icnt, NULL, "negu",
+                      "d,w", tempreg, treg);
+         macro_build ((char *) NULL, &icnt, NULL, "rorv",
+                      "d,t,s", dreg, sreg, tempreg);
+         if (used_at)
+           break;
+         return;
+       }
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "subu",
                   "d,v,t", AT, 0, treg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srlv",
@@ -6650,10 +7020,25 @@ macro2 (ip)
        char *l, *r;
 
        if (imm_expr.X_op != O_constant)
-         as_bad (_("rotate count too large"));
+         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x3f;
-       if (! rot)
-         break;
+       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_arch))
+         {
+           rot = (64 - rot) & 0x3f;
+           if (rot >= 32)
+             macro_build ((char *) NULL, &icnt, NULL, "dror32",
+                          "d,w,<", dreg, sreg, rot - 32);
+           else
+             macro_build ((char *) NULL, &icnt, NULL, "dror",
+                          "d,w,<", dreg, sreg, rot);
+           return;
+         }
+       if (rot == 0)
+         {
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsrl",
+                        "d,w,<", dreg, sreg, 0);
+           return;
+         }
        l = (rot < 0x20) ? "dsll" : "dsll32";
        r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
@@ -6671,10 +7056,20 @@ macro2 (ip)
        unsigned int rot;
 
        if (imm_expr.X_op != O_constant)
-         as_bad (_("rotate count too large"));
+         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
-       if (! rot)
-         break;
+       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_arch))
+         {
+           macro_build ((char *) NULL, &icnt, NULL, "ror",
+                        "d,w,<", dreg, sreg, (32 - rot) & 0x1f);
+           return;
+         }
+       if (rot == 0)
+         {
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
+                        "d,w,<", dreg, sreg, 0);
+           return;
+         }
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll",
                     "d,w,<", AT, sreg, rot);
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
@@ -6685,6 +7080,12 @@ macro2 (ip)
       break;
 
     case M_DROR:
+      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_arch))
+       {
+         macro_build ((char *) NULL, &icnt, NULL, "drorv",
+                      "d,t,s", dreg, sreg, treg);
+         return;
+       }
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsubu",
                   "d,v,t", AT, 0, treg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsllv",
@@ -6696,6 +7097,12 @@ macro2 (ip)
       break;
 
     case M_ROR:
+      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_arch))
+       {
+         macro_build ((char *) NULL, &icnt, NULL, "rorv",
+                      "d,t,s", dreg, sreg, treg);
+         return;
+       }
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "subu",
                   "d,v,t", AT, 0, treg);
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sllv",
@@ -6712,10 +7119,24 @@ macro2 (ip)
        char *l, *r;
 
        if (imm_expr.X_op != O_constant)
-         as_bad (_("rotate count too large"));
+         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x3f;
-       if (! rot)
-         break;
+       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_arch))
+         {
+           if (rot >= 32)
+             macro_build ((char *) NULL, &icnt, NULL, "dror32",
+                          "d,w,<", dreg, sreg, rot - 32);
+           else
+             macro_build ((char *) NULL, &icnt, NULL, "dror",
+                          "d,w,<", dreg, sreg, rot);
+           return;
+         }
+       if (rot == 0)
+         {
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "dsrl",
+                        "d,w,<", dreg, sreg, 0);
+           return;
+         }
        r = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
@@ -6733,10 +7154,20 @@ macro2 (ip)
        unsigned int rot;
 
        if (imm_expr.X_op != O_constant)
-         as_bad (_("rotate count too large"));
+         as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
-       if (! rot)
-         break;
+       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_arch))
+         {
+           macro_build ((char *) NULL, &icnt, NULL, "ror",
+                        "d,w,<", dreg, sreg, rot);
+           return;
+         }
+       if (rot == 0)
+         {
+           macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
+                        "d,w,<", dreg, sreg, 0);
+           return;
+         }
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "srl",
                     "d,w,<", AT, sreg, rot);
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "sll",
@@ -7069,7 +7500,7 @@ macro2 (ip)
        * Is the double cfc1 instruction a bug in the mips assembler;
        * or is there a reason for it?
        */
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "cfc1", "t,G",
@@ -7353,7 +7784,7 @@ mips16_macro (ip)
     case M_REM_3:
       s = "mfhi";
     do_div3:
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -7388,7 +7819,7 @@ mips16_macro (ip)
       s = "ddivu";
       s2 = "mfhi";
     do_divu3:
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
       macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "0,x,y",
@@ -7585,6 +8016,18 @@ validate_mips_insn (opc)
       case ',': break;
       case '(': break;
       case ')': break;
+      case '+':
+       switch (c = *p++)
+         {
+         case 'A': USE_BITS (OP_MASK_SHAMT,    OP_SH_SHAMT);   break;
+         case 'B': USE_BITS (OP_MASK_INSMSB,   OP_SH_INSMSB);  break;
+         case 'C': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
+         default:
+           as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
+                   c, opc->name, opc->args);
+           return 0;
+         }
+       break;
       case '<': USE_BITS (OP_MASK_SHAMT,       OP_SH_SHAMT);   break;
       case '>':        USE_BITS (OP_MASK_SHAMT,        OP_SH_SHAMT);   break;
       case 'A': break;
@@ -7597,6 +8040,7 @@ validate_mips_insn (opc)
       case 'H': USE_BITS (OP_MASK_SEL,         OP_SH_SEL);     break;
       case 'I': break;
       case 'J': USE_BITS (OP_MASK_CODE19,       OP_SH_CODE19);  break;
+      case 'K':        USE_BITS (OP_MASK_RD,           OP_SH_RD);      break;
       case 'L': break;
       case 'M':        USE_BITS (OP_MASK_CCC,          OP_SH_CCC);     break;
       case 'N':        USE_BITS (OP_MASK_BCC,          OP_SH_BCC);     break;
@@ -7635,6 +8079,10 @@ validate_mips_insn (opc)
       case 'P': USE_BITS (OP_MASK_PERFREG,     OP_SH_PERFREG); break;
       case 'U': USE_BITS (OP_MASK_RD,           OP_SH_RD);
                USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
+      case 'e': USE_BITS (OP_MASK_VECBYTE,     OP_SH_VECBYTE); break;
+      case '%': USE_BITS (OP_MASK_VECALIGN,    OP_SH_VECALIGN); break;
+      case '[': break;
+      case ']': break;
       default:
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
@@ -7667,6 +8115,7 @@ mips_ip (str, ip)
   char *argsStart;
   unsigned int regno;
   unsigned int lastregno = 0;
+  unsigned int lastpos = 0;
   char *s_reset;
   char save_c = 0;
 
@@ -7723,23 +8172,24 @@ mips_ip (str, ip)
   argsStart = s;
   for (;;)
     {
-      boolean ok;
+      bfd_boolean ok;
 
       assert (strcmp (insn->name, str) == 0);
 
       if (OPCODE_IS_MEMBER (insn,
                            (mips_opts.isa
+                            | (file_ase_mips16 ? INSN_MIPS16 : 0)
                             | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
                             | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)),
                            mips_arch))
-       ok = true;
+       ok = TRUE;
       else
-       ok = false;
+       ok = FALSE;
 
       if (insn->pinfo != INSN_MACRO)
        {
          if (mips_arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
-           ok = false;
+           ok = FALSE;
        }
 
       if (! ok)
@@ -7755,11 +8205,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)
@@ -7821,18 +8275,84 @@ mips_ip (str, ip)
                return;
 
            case ')':           /* these must match exactly */
+           case '[':
+           case ']':
              if (*s++ == *args)
                continue;
              break;
 
-           case '<':           /* must be at least one digit */
-             /*
-              * According to the manual, if the shift amount is greater
-              * than 31 or less than 0, then the shift amount should be
-              * mod 32.  In reality the mips assembler issues an error.
-              * We issue a warning and mask out all but the low 5 bits.
-              */
-             my_getExpression (&imm_expr, s);
+           case '+':           /* Opcode extension character.  */
+             switch (*++args)
+               {
+                 case 'A':             /* ins/ext "pos".  */
+                   my_getExpression (&imm_expr, s);
+                   check_absolute_expr (ip, &imm_expr);
+                   if ((unsigned long) imm_expr.X_add_number > 31)
+                     {
+                       as_bad (_("Improper position (%lu)"),
+                               (unsigned long) imm_expr.X_add_number);
+                       imm_expr.X_add_number = 0;
+                     }
+                   lastpos = imm_expr.X_add_number;
+                   ip->insn_opcode |= lastpos << OP_SH_SHAMT;
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                   continue;
+
+                 case 'B':             /* "ins" size spec (becomes MSB).  */
+                   my_getExpression (&imm_expr, s);
+                   check_absolute_expr (ip, &imm_expr);
+                   if (imm_expr.X_add_number == 0
+                       || (unsigned long) imm_expr.X_add_number > 32
+                       || ((unsigned long) imm_expr.X_add_number
+                           + lastpos) > 32)
+                     {
+                       as_bad (_("Improper insert size (%lu, position %lu)"),
+                               (unsigned long) imm_expr.X_add_number,
+                               (unsigned long) lastpos);
+                       imm_expr.X_add_number &= OP_MASK_INSMSB;
+                     }
+                   ip->insn_opcode |= (lastpos + imm_expr.X_add_number
+                                       - 1) << OP_SH_INSMSB;
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                   continue;
+
+                 case 'C':             /* "ext" size spec (becomes MSBD).  */
+                   my_getExpression (&imm_expr, s);
+                   check_absolute_expr (ip, &imm_expr);
+                   if (imm_expr.X_add_number == 0
+                       || (unsigned long) imm_expr.X_add_number > 32
+                       || ((unsigned long) imm_expr.X_add_number
+                           + lastpos) > 32)
+                     {
+                       as_bad (_("Improper extract size (%lu, position %lu)"),
+                               (unsigned long) imm_expr.X_add_number,
+                               (unsigned long) lastpos);
+                       imm_expr.X_add_number &= OP_MASK_EXTMSBD;
+                     }
+                   ip->insn_opcode |= (imm_expr.X_add_number
+                                       - 1) << OP_SH_EXTMSBD;
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                   continue;
+
+               default:
+                 as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
+                   *args, insn->name, insn->args);
+                 /* Further processing is fruitless.  */
+                 return;
+               }
+             break;
+
+           case '<':           /* must be at least one digit */
+             /*
+              * According to the manual, if the shift amount is greater
+              * than 31 or less than 0, then the shift amount should be
+              * mod 32.  In reality the mips assembler issues an error.
+              * We issue a warning and mask out all but the low 5 bits.
+              */
+             my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
                {
@@ -7962,6 +8482,7 @@ mips_ip (str, ip)
            case 'w':           /* both dest and target */
            case 'E':           /* coprocessor target register */
            case 'G':           /* coprocessor destination register */
+           case 'K':           /* 'rdhwr' destination register */
            case 'x':           /* ignore register name */
            case 'z':           /* must be zero register */
            case 'U':           /* destination register (clo/clz).  */
@@ -7983,7 +8504,7 @@ mips_ip (str, ip)
                      if (regno > 31)
                        as_bad (_("Invalid register number (%d)"), regno);
                    }
-                 else if (*args == 'E' || *args == 'G')
+                 else if (*args == 'E' || *args == 'G' || *args == 'K')
                    goto notreg;
                  else
                    {
@@ -8057,7 +8578,8 @@ mips_ip (str, ip)
                  if (regno == AT
                      && ! mips_opts.noat
                      && *args != 'E'
-                     && *args != 'G')
+                     && *args != 'G'
+                     && *args != 'K')
                    as_warn (_("Used $at without \".set noat\""));
                  c = *args;
                  if (*s == ' ')
@@ -8087,6 +8609,7 @@ mips_ip (str, ip)
                      break;
                    case 'd':
                    case 'G':
+                   case 'K':
                      ip->insn_opcode |= regno << OP_SH_RD;
                      break;
                    case 'U':
@@ -8522,9 +9045,11 @@ 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;
@@ -8550,11 +9075,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;
                    }
@@ -8640,10 +9160,7 @@ mips_ip (str, ip)
              continue;
 
            case 'p':           /* pc relative offset */
-             if (mips_pic == EMBEDDED_PIC)
-               *offset_reloc = BFD_RELOC_16_PCREL_S2;
-             else
-               *offset_reloc = BFD_RELOC_16_PCREL;
+             *offset_reloc = BFD_RELOC_16_PCREL_S2;
              my_getExpression (&offset_expr, s);
              s = expr_end;
              continue;
@@ -8655,13 +9172,10 @@ 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;
+                         imm_unmatched_hi = TRUE;
                        }
 #ifdef OBJ_ELF
                      else if (c == S_EX_HIGHEST)
@@ -8692,9 +9206,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;
@@ -8748,6 +9262,41 @@ mips_ip (str, ip)
              ip->insn_opcode |= c;
              continue;
 
+           case 'e':
+             /* Must be at least one digit.  */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+
+             if ((unsigned long) imm_expr.X_add_number
+                 > (unsigned long) OP_MASK_VECBYTE)
+               {
+                 as_bad (_("bad byte vector index (%ld)"),
+                          (long) imm_expr.X_add_number);
+                 imm_expr.X_add_number = 0;
+               }
+
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECBYTE;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '%':
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+
+             if ((unsigned long) imm_expr.X_add_number
+                 > (unsigned long) OP_MASK_VECALIGN)
+               {
+                 as_bad (_("bad byte vector index (%ld)"),
+                          (long) imm_expr.X_add_number);
+                 imm_expr.X_add_number = 0;
+               }
+
+             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECALIGN;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
            default:
              as_bad (_("bad char = '%c'\n"), *args);
              internalError ();
@@ -8792,8 +9341,8 @@ mips16_ip (str, ip)
 
   insn_error = NULL;
 
-  mips16_small = false;
-  mips16_ext = false;
+  mips16_small = FALSE;
+  mips16_ext = FALSE;
 
   for (s = str; ISLOWER (*s); ++s)
     ;
@@ -8810,14 +9359,14 @@ mips16_ip (str, ip)
       if (s[1] == 't' && s[2] == ' ')
        {
          *s = '\0';
-         mips16_small = true;
+         mips16_small = TRUE;
          s += 3;
          break;
        }
       else if (s[1] == 'e' && s[2] == ' ')
        {
          *s = '\0';
-         mips16_ext = true;
+         mips16_ext = TRUE;
          s += 3;
          break;
        }
@@ -8828,7 +9377,7 @@ mips16_ip (str, ip)
     }
 
   if (mips_opts.noautoextend && ! mips16_ext)
-    mips16_small = true;
+    mips16_small = TRUE;
 
   if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
     {
@@ -8843,7 +9392,7 @@ mips16_ip (str, ip)
 
       ip->insn_mo = insn;
       ip->insn_opcode = insn->match;
-      ip->use_extend = false;
+      ip->use_extend = FALSE;
       imm_expr.X_op = O_absent;
       imm_reloc[0] = BFD_RELOC_UNUSED;
       imm_reloc[1] = BFD_RELOC_UNUSED;
@@ -8875,7 +9424,7 @@ mips16_ip (str, ip)
                      && insn->pinfo != INSN_MACRO)
                    {
                      mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
-                                   imm_expr.X_add_number, true, mips16_small,
+                                   imm_expr.X_add_number, TRUE, mips16_small,
                                    mips16_ext, &ip->insn_opcode,
                                    &ip->use_extend, &ip->extend);
                      imm_expr.X_op = O_absent;
@@ -9113,10 +9662,10 @@ mips16_ip (str, ip)
                  my_getExpression (&imm_expr, s + sizeof "%gprel" - 1);
                  if (imm_expr.X_op == O_symbol)
                    {
-                     mips16_ext = true;
+                     mips16_ext = TRUE;
                      *imm_reloc = BFD_RELOC_MIPS16_GPREL;
                      s = expr_end;
-                     ip->use_extend = true;
+                     ip->use_extend = TRUE;
                      ip->extend = 0;
                      continue;
                    }
@@ -9392,16 +9941,16 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
      unsigned int line;
      int type;
      offsetT val;
-     boolean warn;
-     boolean small;
-     boolean ext;
+     bfd_boolean warn;
+     bfd_boolean small;
+     bfd_boolean ext;
      unsigned long *insn;
-     boolean *use_extend;
+     bfd_boolean *use_extend;
      unsigned short *extend;
 {
   register const struct mips16_immed_operand *op;
   int mintiny, maxtiny;
-  boolean needext;
+  bfd_boolean needext;
 
   op = mips16_immed_operands;
   while (op->type != type)
@@ -9436,9 +9985,9 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
   if ((val & ((1 << op->shift) - 1)) != 0
       || val < (mintiny << op->shift)
       || val > (maxtiny << op->shift))
-    needext = true;
+    needext = TRUE;
   else
-    needext = false;
+    needext = FALSE;
 
   if (warn && ext && ! needext)
     as_warn_where (file, line,
@@ -9450,7 +9999,7 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
     {
       int insnval;
 
-      *use_extend = false;
+      *use_extend = FALSE;
       insnval = ((val >> op->shift) & ((1 << op->nbits) - 1));
       insnval <<= op->op_shift;
       *insn |= insnval;
@@ -9474,7 +10023,7 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
        as_bad_where (file, line,
                      _("operand value out of range for instruction"));
 
-      *use_extend = true;
+      *use_extend = TRUE;
       if (op->extbits == 16)
        {
          extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
@@ -9815,6 +10364,7 @@ md_number_to_chars (buf, val, n)
 static int support_64bit_objects(void)
 {
   const char **list, **l;
+  int yes;
 
   list = bfd_target_list ();
   for (l = list; *l != NULL; l++)
@@ -9827,12 +10377,13 @@ static int support_64bit_objects(void)
        || strcmp (*l, "elf64-littlemips") == 0)
 #endif
       break;
+  yes = (*l != NULL);
   free (list);
-  return (*l != NULL);
+  return yes;
 }
 #endif /* OBJ_ELF */
 
-CONST char *md_shortopts = "nO::g::G:";
+const char *md_shortopts = "nO::g::G:";
 
 struct option md_longopts[] =
 {
@@ -9884,8 +10435,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)
@@ -9912,8 +10463,18 @@ struct option md_longopts[] =
   {"mdmx", no_argument, NULL, OPTION_MDMX},
 #define OPTION_NO_MDMX (OPTION_MD_BASE + 36)
   {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
+#define OPTION_FIX_VR4122 (OPTION_MD_BASE + 37)
+#define OPTION_NO_FIX_VR4122 (OPTION_MD_BASE + 38)
+  {"mfix-vr4122-bugs",    no_argument, NULL, OPTION_FIX_VR4122},
+  {"no-mfix-vr4122-bugs", no_argument, NULL, OPTION_NO_FIX_VR4122},
+#define OPTION_RELAX_BRANCH (OPTION_MD_BASE + 39)
+#define OPTION_NO_RELAX_BRANCH (OPTION_MD_BASE + 40)
+  {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
+  {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
+#define OPTION_MIPS32R2 (OPTION_MD_BASE + 41)
+  {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MD_BASE + 37)
+#define OPTION_ELF_BASE    (OPTION_MD_BASE + 42)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
@@ -9929,11 +10490,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;
@@ -9989,130 +10572,72 @@ 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_MIPS32R2:
+      file_mips_isa = ISA_MIPS32R2;
       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:
@@ -10128,12 +10653,12 @@ md_parse_option (c, arg)
 
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
-      mips_no_prev_insn (false);
+      mips_no_prev_insn (FALSE);
       break;
 
     case OPTION_NO_MIPS16:
       mips_opts.mips16 = 0;
-      mips_no_prev_insn (false);
+      mips_no_prev_insn (FALSE);
       break;
 
     case OPTION_MIPS3D:
@@ -10154,6 +10679,22 @@ md_parse_option (c, arg)
       g_switch_value = 0x7fffffff;
       break;
 
+    case OPTION_FIX_VR4122:
+      mips_fix_4122_bugs = 1;
+      break;
+
+    case OPTION_NO_FIX_VR4122:
+      mips_fix_4122_bugs = 0;
+      break;
+
+    case OPTION_RELAX_BRANCH:
+      mips_relax_branch = 1;
+      break;
+
+    case OPTION_NO_RELAX_BRANCH:
+      mips_relax_branch = 0;
+      break;
+
 #ifdef OBJ_ELF
       /* When generating ELF code, we permit -KPIC and -call_shared to
         select SVR4_PIC, and -non_shared to select no PIC.  This is
@@ -10215,7 +10756,7 @@ md_parse_option (c, arg)
          as_bad (_("-32 is supported for ELF format only"));
          return 0;
        }
-      mips_opts.abi = O32_ABI;
+      mips_abi = O32_ABI;
       break;
 
     case OPTION_N32:
@@ -10224,7 +10765,7 @@ md_parse_option (c, arg)
          as_bad (_("-n32 is supported for ELF format only"));
          return 0;
        }
-      mips_opts.abi = N32_ABI;
+      mips_abi = N32_ABI;
       break;
 
     case OPTION_64:
@@ -10233,7 +10774,7 @@ md_parse_option (c, arg)
          as_bad (_("-64 is supported for ELF format only"));
          return 0;
        }
-      mips_opts.abi = N64_ABI;
+      mips_abi = N64_ABI;
       if (! support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
@@ -10241,20 +10782,18 @@ 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
@@ -10265,20 +10804,20 @@ md_parse_option (c, arg)
          return 0;
        }
       if (strcmp (arg, "32") == 0)
-       mips_opts.abi = O32_ABI;
+       mips_abi = O32_ABI;
       else if (strcmp (arg, "o64") == 0)
-       mips_opts.abi = O64_ABI;
+       mips_abi = O64_ABI;
       else if (strcmp (arg, "n32") == 0)
-       mips_opts.abi = N32_ABI;
+       mips_abi = N32_ABI;
       else if (strcmp (arg, "64") == 0)
        {
-         mips_opts.abi = N64_ABI;
+         mips_abi = N64_ABI;
          if (! support_64bit_objects())
            as_fatal (_("No compiled in support for 64 bit object file "
                        "format"));
        }
       else if (strcmp (arg, "eabi") == 0)
-       mips_opts.abi = EABI_ABI;
+       mips_abi = EABI_ABI;
       else
        {
          as_fatal (_("invalid abi -mabi=%s"), arg);
@@ -10288,12 +10827,22 @@ md_parse_option (c, arg)
 #endif /* OBJ_ELF */
 
     case OPTION_M7000_HILO_FIX:
-      mips_7000_hilo_fix = true;
+      mips_7000_hilo_fix = TRUE;
       break;
 
     case OPTION_MNO_7000_HILO_FIX:
-      mips_7000_hilo_fix = false;
+      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;
@@ -10301,144 +10850,40 @@ md_parse_option (c, arg)
 
   return 1;
 }
+\f
+/* Set up globals to generate code for the ISA or processor
+   described by INFO.  */
 
 static void
-show (stream, string, col_p, first_p)
-     FILE *stream;
-     char *string;
-     int *col_p;
-     int *first_p;
+mips_set_architecture (info)
+     const struct mips_cpu_info *info;
 {
-  if (*first_p)
-    {
-      fprintf (stream, "%24s", "");
-      *col_p = 24;
-    }
-  else
-    {
-      fprintf (stream, ", ");
-      *col_p += 2;
-    }
-
-  if (*col_p + strlen (string) > 72)
+  if (info != 0)
     {
-      fprintf (stream, "\n%24s", "");
-      *col_p = 24;
+      mips_arch_info = info;
+      mips_arch = info->cpu;
+      mips_opts.isa = info->isa;
     }
-
-  fprintf (stream, "%s", string);
-  *col_p += strlen (string);
-
-  *first_p = 0;
 }
 
-void
-md_show_usage (stream)
-     FILE *stream;
-{
-  int column, first;
-
-  fprintf (stream, _("\
-MIPS options:\n\
--membedded-pic         generate embedded position independent code\n\
--EB                    generate big endian output\n\
--EL                    generate little endian output\n\
--g, -g2                        do not remove 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;
-
-  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);
-
-  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;
+/* Likewise for tuning.  */
 
-  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);
+static void
+mips_set_tune (info)
+     const struct mips_cpu_info *info;
+{
+  if (info != 0)
+    {
+      mips_tune_info = info;
+      mips_tune = info->cpu;
+    }
+}
 
-  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
-}
-\f
 void
 mips_after_parse_args ()
 {
-  const char *cpu;
-  char *a = NULL;
-  int mips_isa_from_cpu;
-  const struct mips_cpu_info *ci;
-
   /* GP relative stuff not working for PE */
   if (strncmp (TARGET_OS, "pe", 2) == 0
       && g_switch_value != 0)
@@ -10448,184 +10893,88 @@ mips_after_parse_args ()
       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;
-    }
+  /* 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.  */
 
-  /* 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_arch_string != 0)
+    mips_set_architecture (mips_parse_cpu ("-march", mips_arch_string));
 
-  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_tune_string != 0)
+    mips_set_tune (mips_parse_cpu ("-mtune", mips_tune_string));
 
-#if 1
-  /* For backward compatibility, let -mipsN set various defaults.  */
-  /* This code should go away, to be replaced with something rather more
-     draconian.  Until GCC 3.1 has been released for some reasonable
-     amount of time, however, we need to support this.  */
-  if (mips_opts.isa != ISA_UNKNOWN)
+  if (file_mips_isa != ISA_UNKNOWN)
     {
-      /* Translate -mipsN to the appropriate settings of file_mips_gp32
-        and file_mips_fp32.  Tag binaries as using the mipsN ISA.  */
-      if (file_mips_gp32 < 0)
-       {
-         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
-           file_mips_gp32 = 0;
-         else
-           file_mips_gp32 = 1;
-       }
-      if (file_mips_fp32 < 0)
-       {
-         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
-           file_mips_fp32 = 0;
-         else
-           file_mips_fp32 = 1;
-       }
-
-      ci = mips_cpu_info_from_isa (mips_opts.isa);
-      assert (ci != NULL);
-      /* -mipsN has higher priority than -mcpu but lower than -march.  */
-      if (mips_arch == CPU_UNKNOWN)
-       mips_arch = ci->cpu;
-
-      /* Default mips_abi.  */
-      if (mips_opts.abi == NO_ABI)
+      /* 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)
        {
-         if (mips_opts.isa == ISA_MIPS1 || mips_opts.isa == ISA_MIPS2)
-           mips_opts.abi = O32_ABI;
-         else if (mips_opts.isa == ISA_MIPS3 || mips_opts.isa == ISA_MIPS4)
-           mips_opts.abi = O64_ABI;
+         /* -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));
     }
 
-  if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
-    {
-      ci = mips_cpu_info_from_cpu (mips_cpu);
-      assert (ci != NULL);
-      mips_arch = ci->cpu;
-      as_warn (_("The -mcpu option is deprecated.  Please use -march and "
-                "-mtune instead."));
-    }
-
-  /* Set tune from -mcpu, not from -mipsN.  */
-  if (mips_tune == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
-    {
-      ci = mips_cpu_info_from_cpu (mips_cpu);
-      assert (ci != NULL);
-      mips_tune = ci->cpu;
-    }
-
-  /* At this point, mips_arch will either be CPU_UNKNOWN if no ARCH was
-     specified on the command line, or some other value if one was.
-     Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
-     the command line, or will be set otherwise if one was.  */
+  if (mips_arch_info == 0)
+    mips_set_architecture (mips_parse_cpu ("default CPU",
+                                          MIPS_CPU_STRING_DEFAULT));
 
-  if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
-    /* Handled above.  */;
-#else
-  if (mips_arch == CPU_UNKNOWN && mips_cpu != CPU_UNKNOWN)
-    {
-      ci = mips_cpu_info_from_cpu (mips_cpu);
-      assert (ci != NULL);
-      mips_arch = ci->cpu;
-      as_warn (_("The -mcpu option is deprecated.  Please use -march and "
-                "-mtune instead."));
-    }
+  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);
 
-  /* 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.  */
+  /* Optimize for mips_arch, unless -mtune selects a different processor.  */
+  if (mips_tune_info == 0)
+    mips_set_tune (mips_arch_info);
 
-  if (mips_arch != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
-    {
-      /* We have to check if the isa is the default isa of arch.  Otherwise
-         we'll get invalid object file headers.  */
-      ci = mips_cpu_info_from_cpu (mips_arch);
-      assert (ci != NULL);
-      if (mips_opts.isa != ci->isa)
-       {
-         /* This really should be an error instead of a warning, but old
-            compilers only have -mcpu which sets both arch and tune.  For
-            now, we discard arch and preserve tune.  */
-         as_warn (_("The -march option is incompatible to -mipsN and "
-                    "therefore ignored."));
-         if (mips_tune == CPU_UNKNOWN)
-           mips_tune = mips_arch;
-         ci = mips_cpu_info_from_isa (mips_opts.isa);
-         assert (ci != NULL);
-         mips_arch = ci->cpu;
-       }
-    }
-#endif
-  else if (mips_arch != CPU_UNKNOWN && mips_opts.isa == ISA_UNKNOWN)
+  if (file_mips_gp32 >= 0)
     {
-      /* 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;
+      /* 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
     {
-      /* 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;
+      /* 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));
     }
 
-  if (mips_tune == CPU_UNKNOWN)
-    mips_tune = mips_arch;
+  /* ??? 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;
 
-  ci = mips_cpu_info_from_cpu (mips_arch);
-  assert (ci != NULL);
-  mips_isa_from_cpu = ci->isa;
+  /* End of GCC-shared inference code.  */
 
-  /* End of TARGET_CPU processing, get rid of malloced memory
-     if necessary.  */
-  cpu = NULL;
-  if (a != NULL)
-    {
-      free (a);
-      a = NULL;
-    }
+  /* ??? 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 they asked for mips1 or mips2 and a cpu that is
-     mips3 or greater, then mark the object file 32BITMODE.  */
-  if (mips_isa_from_cpu != ISA_UNKNOWN
-      && ! ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && ISA_HAS_64BIT_REGS (mips_isa_from_cpu))
-    mips_32bitmode = 1;
-
   /* If the selected architecture includes support for ASEs, enable
      generation of code for them.  */
   if (mips_opts.mips16 == -1)
@@ -10635,21 +10984,22 @@ mips_after_parse_args ()
   if (mips_opts.ase_mdmx == -1)
     mips_opts.ase_mdmx = (CPU_HAS_MDMX (mips_arch)) ? 1 : 0;
 
-  if (file_mips_gp32 < 0)
-    file_mips_gp32 = 0;
-  if (file_mips_fp32 < 0)
-    file_mips_fp32 = 0;
-
   file_mips_isa = mips_opts.isa;
-  file_mips_abi = mips_opts.abi;
   file_ase_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
@@ -10667,14 +11017,7 @@ md_pcrel_from (fixP)
   if (OUTPUT_FLAVOR != bfd_target_aout_flavour
       && fixP->fx_addsy != (symbolS *) NULL
       && ! S_IS_DEFINED (fixP->fx_addsy))
-    {
-      /* This makes a branch to an undefined symbol be a branch to the
-        current location.  */
-      if (mips_pic == EMBEDDED_PIC)
-       return 4;
-      else
-       return 1;
-    }
+    return 4;
 
   /* Return the address of the delay slot.  */
   return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
@@ -10806,7 +11149,8 @@ mips_force_relocation (fixp)
      fixS *fixp;
 {
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || S_FORCE_RELOC (fixp->fx_addsy))
     return 1;
 
   if (HAVE_NEWABI
@@ -10835,13 +11179,13 @@ mips_need_elf_addend_fixup (fixP)
     return 1;
   if (mips_pic != EMBEDDED_PIC
       && (S_IS_WEAK (fixP->fx_addsy)
-         || S_IS_EXTERN (fixP->fx_addsy))
+         || S_IS_EXTERNAL (fixP->fx_addsy))
       && !S_IS_COMMON (fixP->fx_addsy))
     return 1;
   if (symbol_used_in_reloc_p (fixP->fx_addsy)
       && (((bfd_get_section_flags (stdoutput,
                                   S_GET_SEGMENT (fixP->fx_addsy))
-           & SEC_LINK_ONCE) != 0)
+           & (SEC_LINK_ONCE | SEC_MERGE)) != 0)
          || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
                       ".gnu.linkonce",
                       sizeof (".gnu.linkonce") - 1)))
@@ -10861,6 +11205,12 @@ md_apply_fix3 (fixP, valP, seg)
   bfd_byte *buf;
   long insn;
   valueT value;
+  static int previous_fx_r_type = 0;
+
+  /* FIXME: Maybe just return for all reloc types not listed below?
+     Eric Christopher says: "This is stupid, please rewrite md_apply_fix3. */
+  if (fixP->fx_r_type == BFD_RELOC_8)
+      return;
 
   assert (fixP->fx_size == 4
          || fixP->fx_r_type == BFD_RELOC_16
@@ -10892,17 +11242,32 @@ md_apply_fix3 (fixP, valP, seg)
     {
       if (mips_need_elf_addend_fixup (fixP))
        {
+         reloc_howto_type *howto;
          valueT symval = S_GET_VALUE (fixP->fx_addsy);
 
          value -= symval;
-         if (value != 0 && ! fixP->fx_pcrel)
+
+         howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+         if (value != 0 && howto && howto->partial_inplace
+             && (! fixP->fx_pcrel || howto->pcrel_offset))
            {
              /* In this case, the bfd_install_relocation routine will
                 incorrectly add the symbol value back in.  We just want
-                the addend to appear in the object file.  */
-             value -= symval;
+                the addend to appear in the object file.
 
-             /* Make sure the addend is still non-zero.  If it became zero
+                howto->pcrel_offset is added for R_MIPS_PC16, which is
+                generated for code like
+
+                       globl g1 .text
+                       .text
+                       .space 20
+                g1:
+                x:
+                       bal g1
+              */
+             value -= symval;
+
+             /* Make sure the addend is still non-zero.  If it became zero
                 after the last operation, set it to a spurious value and
                 subtract the same value from the object file's contents.  */
              if (value == 0)
@@ -10913,12 +11278,8 @@ md_apply_fix3 (fixP, valP, seg)
                     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,
@@ -10951,8 +11312,7 @@ md_apply_fix3 (fixP, valP, seg)
          /* BFD's REL handling, for MIPS, is _very_ weird.
             This gives the right results, but it can't possibly
             be the way things are supposed to work.  */
-         if ((fixP->fx_r_type != BFD_RELOC_16_PCREL
-              && fixP->fx_r_type != BFD_RELOC_16_PCREL_S2)
+         if (fixP->fx_r_type != BFD_RELOC_16_PCREL_S2
              || S_GET_SEGMENT (fixP->fx_addsy) != undefined_section)
            value += fixP->fx_frag->fr_address + fixP->fx_where;
        }
@@ -10961,8 +11321,17 @@ md_apply_fix3 (fixP, valP, seg)
 
   fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc.  */
 
-  if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel)
+  /* We are not done if this is a composite relocation to set up gp.  */
+  if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel
+      && !(fixP->fx_r_type == BFD_RELOC_MIPS_SUB
+          || (fixP->fx_r_type == BFD_RELOC_64
+              && (previous_fx_r_type == BFD_RELOC_GPREL32
+                  || previous_fx_r_type == BFD_RELOC_GPREL16))
+          || (previous_fx_r_type == BFD_RELOC_MIPS_SUB
+              && (fixP->fx_r_type == BFD_RELOC_HI16_S
+                  || fixP->fx_r_type == BFD_RELOC_LO16))))
     fixP->fx_done = 1;
+  previous_fx_r_type = fixP->fx_r_type;
 
   switch (fixP->fx_r_type)
     {
@@ -11117,15 +11486,12 @@ md_apply_fix3 (fixP, valP, seg)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Branch to odd address (%lx)"), (long) value);
 
-      /* Fall through.  */
-
-    case BFD_RELOC_16_PCREL:
       /*
        * We need to save the bits in the instruction since fixup_segment()
        * might be deleting the relocation entry (i.e., a branch within
        * the current segment).
        */
-      if (!fixP->fx_done && value != 0)
+      if (!fixP->fx_done && (value != 0 || HAVE_NEWABI))
        break;
       /* If 'value' is zero, the remaining reloc code won't actually
         do the store, so it must be done here.  This is probably
@@ -11172,13 +11538,9 @@ md_apply_fix3 (fixP, valP, seg)
            }
          else
            {
-             /* FIXME.  It would be possible in principle to handle
-                 conditional branches which overflow.  They could be
-                 transformed into a branch around a jump.  This would
-                 require setting up variant frags for each different
-                 branch type.  The native MIPS assembler attempts to
-                 handle these cases, but it appears to do it
-                 incorrectly.  */
+             /* If we got here, we have branch-relaxation disabled,
+                and there's nothing we can do to fix this instruction
+                without turning it into a longer sequence.  */
              as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("Branch out of range"));
            }
@@ -11315,7 +11677,7 @@ mips_align (to, fill, label)
      int fill;
      symbolS *label;
 {
-  mips_emit_delays (false);
+  mips_emit_delays (FALSE);
   frag_align (to, fill, 0);
   record_alignment (now_seg, to);
   if (label != NULL)
@@ -11381,7 +11743,7 @@ s_align (x)
 void
 mips_flush_pending_output ()
 {
-  mips_emit_delays (false);
+  mips_emit_delays (FALSE);
   mips_clear_insn_labels ();
 }
 
@@ -11408,7 +11770,7 @@ s_change_sec (sec)
   obj_elf_section_change_hook ();
 #endif
 
-  mips_emit_delays (false);
+  mips_emit_delays (FALSE);
   switch (sec)
     {
     case 't':
@@ -11474,6 +11836,66 @@ s_change_sec (sec)
   auto_align = 1;
 }
 
+void
+s_change_section (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+#ifdef OBJ_ELF
+  char *section_name;
+  char c;
+  char next_c;
+  int section_type;
+  int section_flag;
+  int section_entry_size;
+  int section_alignment;
+
+  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+    return;
+
+  section_name = input_line_pointer;
+  c = get_symbol_end ();
+  if (c)
+    next_c = *(input_line_pointer + 1);
+
+  /* Do we have .section Name<,"flags">?  */
+  if (c != ',' || (c == ',' && next_c == '"'))
+    {
+      /* just after name is now '\0'.  */
+      *input_line_pointer = c;
+      input_line_pointer = section_name;
+      obj_elf_section (ignore);
+      return;
+    }
+  input_line_pointer++;
+
+  /* Do we have .section Name<,type><,flag><,entry_size><,alignment>  */
+  if (c == ',')
+    section_type = get_absolute_expression ();
+  else
+    section_type = 0;
+  if (*input_line_pointer++ == ',')
+    section_flag = get_absolute_expression ();
+  else
+    section_flag = 0;
+  if (*input_line_pointer++ == ',')
+    section_entry_size = get_absolute_expression ();
+  else
+    section_entry_size = 0;
+  if (*input_line_pointer++ == ',')
+    section_alignment = get_absolute_expression ();
+  else
+    section_alignment = 0;
+
+  section_name = xstrdup (section_name);
+
+  obj_elf_change_section (section_name, section_type, section_flag,
+                         section_entry_size, 0, 0, 0);
+
+  if (now_seg->name != section_name)
+    free (section_name);
+#endif /* OBJ_ELF */
+}
+
 void
 mips_enable_auto_align ()
 {
@@ -11487,7 +11909,7 @@ s_cons (log_size)
   symbolS *label;
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
-  mips_emit_delays (false);
+  mips_emit_delays (FALSE);
   if (log_size > 0 && auto_align)
     mips_align (log_size, 0, label);
   mips_clear_insn_labels ();
@@ -11502,7 +11924,7 @@ s_float_cons (type)
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
 
-  mips_emit_delays (false);
+  mips_emit_delays (FALSE);
 
   if (auto_align)
     {
@@ -11643,7 +12065,7 @@ s_mipsset (x)
     }
   else if (strcmp (name, "noreorder") == 0)
     {
-      mips_emit_delays (true);
+      mips_emit_delays (TRUE);
       mips_opts.noreorder = 1;
       mips_any_noreorder = 1;
     }
@@ -11697,31 +12119,49 @@ s_mipsset (x)
     mips_opts.ase_mdmx = 0;
   else if (strncmp (name, "mips", 4) == 0)
     {
-      int isa;
+      int reset = 0;
 
       /* Permit the user to change the ISA on the fly.  Needless to
         say, misuse can cause serious problems.  */
-      isa = atoi (name + 4);
-      switch (isa)
+      if (strcmp (name, "mips0") == 0)
+       {
+         reset = 1;
+         mips_opts.isa = file_mips_isa;
+       }
+      else if (strcmp (name, "mips1") == 0)
+       mips_opts.isa = ISA_MIPS1;
+      else if (strcmp (name, "mips2") == 0)
+       mips_opts.isa = ISA_MIPS2;
+      else if (strcmp (name, "mips3") == 0)
+       mips_opts.isa = ISA_MIPS3;
+      else if (strcmp (name, "mips4") == 0)
+       mips_opts.isa = ISA_MIPS4;
+      else if (strcmp (name, "mips5") == 0)
+       mips_opts.isa = ISA_MIPS5;
+      else if (strcmp (name, "mips32") == 0)
+       mips_opts.isa = ISA_MIPS32;
+      else if (strcmp (name, "mips32r2") == 0)
+       mips_opts.isa = ISA_MIPS32R2;
+      else if (strcmp (name, "mips64") == 0)
+       mips_opts.isa = ISA_MIPS64;
+      else
+       as_bad (_("unknown ISA level %s"), name + 4);
+
+      switch (mips_opts.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:
+       case ISA_MIPS1:
+       case ISA_MIPS2:
+       case ISA_MIPS32:
+       case ISA_MIPS32R2:
          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;
+       case ISA_MIPS3:
+       case ISA_MIPS4:
+       case ISA_MIPS5:
+       case ISA_MIPS64:
          mips_opts.gp32 = 0;
          mips_opts.fp32 = 0;
          break;
@@ -11729,18 +12169,10 @@ s_mipsset (x)
          as_bad (_("unknown ISA level %s"), name + 4);
          break;
        }
-
-      switch (isa)
+      if (reset)
        {
-       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;
+         mips_opts.gp32 = file_mips_gp32;
+         mips_opts.fp32 = file_mips_fp32;
        }
     }
   else if (strcmp (name, "autoextend") == 0)
@@ -11768,7 +12200,7 @@ s_mipsset (x)
          /* If we're changing the reorder mode we need to handle
              delay slots correctly.  */
          if (s->options.noreorder && ! mips_opts.noreorder)
-           mips_emit_delays (true);
+           mips_emit_delays (TRUE);
          else if (! s->options.noreorder && mips_opts.noreorder)
            {
              if (prev_nop_frag != NULL)
@@ -11880,7 +12312,7 @@ s_cpsetup (ignore)
   expressionS ex_sym;
   int reg1;
   int icnt = 0;
-  char *sym;
+  char *f;
 
   /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
      We also need NewABI support.  */
@@ -11919,15 +12351,7 @@ s_cpsetup (ignore)
   else
     ++input_line_pointer;
   SKIP_WHITESPACE ();
-  sym = input_line_pointer;
-  while (ISALNUM (*input_line_pointer))
-    ++input_line_pointer;
-  *input_line_pointer = 0;
-
-  ex_sym.X_op = O_symbol;
-  ex_sym.X_add_symbol = symbol_find_or_make (sym);
-  ex_sym.X_op_symbol = NULL;
-  ex_sym.X_add_number = 0;
+  expression (&ex_sym);
 
   if (mips_cpreturn_register == -1)
     {
@@ -11943,14 +12367,25 @@ 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, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
-  fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_HI16_S);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_HI16_S);
+
+  f = frag_more (0);
   macro_build ((char *) NULL, &icnt, &ex_sym, "addiu", "t,r,j",
               mips_gp_register, mips_gp_register, (int) BFD_RELOC_GPREL16);
-  fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
-  fix_new (frag_now, prev_insn_where, 0, NULL, 0, 0, BFD_RELOC_LO16);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_MIPS_SUB);
+  fix_new (frag_now, f - frag_now->fr_literal,
+          0, NULL, 0, 0, BFD_RELOC_LO16);
+
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
               HAVE_64BIT_ADDRESSES ? "daddu" : "addu", "d,v,t",
               mips_gp_register, mips_gp_register, reg1);
@@ -12001,8 +12436,9 @@ s_cprestore (ignore)
   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)", mips_gp_register, (int) BFD_RELOC_LO16, SP);
+  macro_build_ldst_constoffset ((char *) NULL, &icnt, &ex,
+                               HAVE_32BIT_ADDRESSES ? "sw" : "sd",
+                               mips_gp_register, SP);
 
   demand_empty_rest_of_line ();
 }
@@ -12085,7 +12521,7 @@ s_gpword (ignore)
     }
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
-  mips_emit_delays (true);
+  mips_emit_delays (TRUE);
   if (auto_align)
     mips_align (2, 0, label);
   mips_clear_insn_labels ();
@@ -12100,12 +12536,56 @@ 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, false,
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
               BFD_RELOC_GPREL32);
 
   demand_empty_rest_of_line ();
 }
 
+static void
+s_gpdword (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  symbolS *label;
+  expressionS ex;
+  char *p;
+
+  /* When not generating PIC code, this is treated as .dword.  */
+  if (mips_pic != SVR4_PIC)
+    {
+      s_cons (3);
+      return;
+    }
+
+  label = insn_labels != NULL ? insn_labels->label : NULL;
+  mips_emit_delays (TRUE);
+  if (auto_align)
+    mips_align (3, 0, label);
+  mips_clear_insn_labels ();
+
+  expression (&ex);
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad (_("Unsupported use of .gpdword"));
+      ignore_rest_of_line ();
+    }
+
+  p = frag_more (8);
+  md_number_to_chars (p, (valueT) 0, 8);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, FALSE,
+              BFD_RELOC_GPREL32);
+
+  /* GPREL32 composed with 64 gives a 64-bit GP offset.  */
+  ex.X_op = O_absent;
+  ex.X_add_symbol = 0;
+  ex.X_add_number = 0;
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &ex, FALSE,
+              BFD_RELOC_64);
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle the .cpadd pseudo-op.  This is used when dealing with switch
    tables in SVR4 PIC code.  */
 
@@ -12116,9 +12596,8 @@ s_cpadd (ignore)
   int icnt = 0;
   int reg;
 
-  /* This is ignored when not generating SVR4 PIC code or if this is NewABI
-     code.  */
-  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
+  /* This is ignored when not generating SVR4 PIC code.  */
+  if (mips_pic != SVR4_PIC)
     {
       s_ignore (0);
       return;
@@ -12594,6 +13073,73 @@ mips16_extended_frag (fragp, sec, stretch)
     return 0;
 }
 
+/* Compute the length of a branch sequence, and adjust the
+   RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the
+   worst-case length is computed, with UPDATE being used to indicate
+   whether an unconditional (-1), branch-likely (+1) or regular (0)
+   branch is to be computed.  */
+static int
+relaxed_branch_length (fragp, sec, update)
+     fragS *fragp;
+     asection *sec;
+     int update;
+{
+  bfd_boolean toofar;
+  int length;
+
+  if (fragp
+      && S_IS_DEFINED (fragp->fr_symbol)
+      && sec == S_GET_SEGMENT (fragp->fr_symbol))
+    {
+      addressT addr;
+      offsetT val;
+
+      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+
+      addr = fragp->fr_address + fragp->fr_fix + 4;
+
+      val -= addr;
+
+      toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
+    }
+  else if (fragp)
+    /* If the symbol is not defined or it's in a different segment,
+       assume the user knows what's going on and emit a short
+       branch.  */
+    toofar = FALSE;
+  else
+    toofar = TRUE;
+
+  if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+    fragp->fr_subtype
+      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype),
+                            RELAX_BRANCH_LIKELY (fragp->fr_subtype),
+                            RELAX_BRANCH_LINK (fragp->fr_subtype),
+                            toofar);
+
+  length = 4;
+  if (toofar)
+    {
+      if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
+       length += 8;
+
+      if (mips_pic != NO_PIC)
+       {
+         /* Additional space for PIC loading of target address.  */
+         length += 8;
+         if (mips_opts.isa == ISA_MIPS1)
+           /* Additional space for $at-stabilizing nop.  */
+           length += 4;
+       }
+
+      /* If branch is conditional.  */
+      if (fragp ? !RELAX_BRANCH_UNCOND (fragp->fr_subtype) : (update >= 0))
+       length += 8;
+    }
+
+  return length;
+}
+
 /* Estimate the size of a frag before relaxing.  Unless this is the
    mips16, we are not really relaxing here, and the final size is
    encoded in the subtype information.  For the mips16, we have to
@@ -12605,7 +13151,15 @@ md_estimate_size_before_relax (fragp, segtype)
      asection *segtype;
 {
   int change = 0;
-  boolean linkonce = false;
+  bfd_boolean linkonce = FALSE;
+
+  if (RELAX_BRANCH_P (fragp->fr_subtype))
+    {
+
+      fragp->fr_var = relaxed_branch_length (fragp, segtype, FALSE);
+
+      return fragp->fr_var;
+    }
 
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     /* We don't want to modify the EXTENDED bit here; it might get us
@@ -12643,14 +13197,14 @@ md_estimate_size_before_relax (fragp, segtype)
        {
          if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
              != 0)
-           linkonce = true;
+           linkonce = TRUE;
 
          /* The GNU toolchain uses an extension for ELF: a section
             beginning with the magic string .gnu.linkonce is a linkonce
             section.  */
          if (strncmp (segment_name (symsec), ".gnu.linkonce",
                       sizeof ".gnu.linkonce" - 1) == 0)
-           linkonce = true;
+           linkonce = TRUE;
        }
 
       /* This must duplicate the test in adjust_reloc_syms.  */
@@ -12662,7 +13216,8 @@ md_estimate_size_before_relax (fragp, segtype)
                /* A global or weak symbol is treated as external.  */
                && (OUTPUT_FLAVOR != bfd_target_elf_flavour
                    || (! S_IS_WEAK (sym)
-                       && (! S_IS_EXTERN (sym) || mips_pic == EMBEDDED_PIC)))
+                       && (! S_IS_EXTERNAL (sym)
+                           || mips_pic == EMBEDDED_PIC)))
 #endif
                );
     }
@@ -12700,26 +13255,23 @@ int
 mips_fix_adjustable (fixp)
      fixS *fixp;
 {
-#ifdef OBJ_ELF
-  /* Prevent all adjustments to global symbols.  */
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && mips_pic != EMBEDDED_PIC
-      && (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
-    return 0;
-#endif
   if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
     return 0;
+
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
+
   if (fixp->fx_addsy == NULL)
     return 1;
+
 #ifdef OBJ_ELF
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour
       && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
       && fixp->fx_subsy == NULL)
     return 0;
 #endif
+
   return 1;
 }
 
@@ -12803,14 +13355,15 @@ 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_GPREL16
+      && ((fixp->fx_r_type == BFD_RELOC_GPREL16
+          && ! HAVE_NEWABI)
          || 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
          || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_LO16
          || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_HI16
          || fixp->fx_r_type == BFD_RELOC_MIPS_CALL_LO16)
-      && ! HAVE_NEWABI)
+    )
     {
       arelent *reloc2;
 
@@ -12871,15 +13424,32 @@ tc_gen_reloc (section, fixp)
              abort ();
            case BFD_RELOC_MIPS_GOT16:
              break;
-           case BFD_RELOC_MIPS_CALL16:
            case BFD_RELOC_MIPS_GOT_LO16:
            case BFD_RELOC_MIPS_CALL_LO16:
              fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
              break;
+           case BFD_RELOC_MIPS_CALL16:
+             if (HAVE_NEWABI)
+               {
+                 /* BFD_RELOC_MIPS_GOT16;*/
+                 fixp->fx_r_type = BFD_RELOC_MIPS_GOT_PAGE;
+                 reloc2->howto = bfd_reloc_type_lookup
+                   (stdoutput, BFD_RELOC_MIPS_GOT_OFST);
+               }
+             else
+               fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
+             break;
            }
        }
       else
        abort ();
+
+      /* newabi uses R_MIPS_GOT_DISP for local symbols */
+      if (HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_MIPS_GOT_LO16)
+       {
+         fixp->fx_r_type = BFD_RELOC_MIPS_GOT_DISP;
+         retval[1] = NULL;
+       }
     }
 
   /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
@@ -12933,7 +13503,7 @@ tc_gen_reloc (section, fixp)
      stop md_apply_fix3 from subtracting twice in the first place since
      the fake addend is required for variant frags above.  */
   if (fixp->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && code == BFD_RELOC_GPREL16
+      && (code == BFD_RELOC_GPREL16 || code == BFD_RELOC_MIPS16_GPREL)
       && reloc->addend != 0
       && mips_need_elf_addend_fixup (fixp))
     reloc->addend += S_GET_VALUE (fixp->fx_addsy);
@@ -12965,10 +13535,20 @@ tc_gen_reloc (section, fixp)
    the current size of the frag should change.  */
 
 int
-mips_relax_frag (fragp, stretch)
+mips_relax_frag (sec, fragp, stretch)
+     asection *sec;
      fragS *fragp;
      long stretch;
 {
+  if (RELAX_BRANCH_P (fragp->fr_subtype))
+    {
+      offsetT old_var = fragp->fr_var;
+
+      fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE);
+
+      return fragp->fr_var - old_var;
+    }
+
   if (! RELAX_MIPS16_P (fragp->fr_subtype))
     return 0;
 
@@ -13001,15 +13581,223 @@ md_convert_frag (abfd, asec, fragp)
   int old, new;
   char *fixptr;
 
+  if (RELAX_BRANCH_P (fragp->fr_subtype))
+    {
+      bfd_byte *buf;
+      unsigned long insn;
+      expressionS exp;
+      fixS *fixp;
+
+      buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
+
+      if (target_big_endian)
+       insn = bfd_getb32 (buf);
+      else
+       insn = bfd_getl32 (buf);
+
+      if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+       {
+         /* We generate a fixup instead of applying it right now
+            because, if there are linker relaxations, we're going to
+            need the relocations.  */
+         exp.X_op = O_symbol;
+         exp.X_add_symbol = fragp->fr_symbol;
+         exp.X_add_number = fragp->fr_offset;
+
+         fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+                             4, &exp, 1,
+                             BFD_RELOC_16_PCREL_S2);
+         fixp->fx_file = fragp->fr_file;
+         fixp->fx_line = fragp->fr_line;
+
+         md_number_to_chars ((char *)buf, insn, 4);
+         buf += 4;
+       }
+      else
+       {
+         int i;
+
+         as_warn_where (fragp->fr_file, fragp->fr_line,
+                        _("relaxed out-of-range branch into a jump"));
+
+         if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
+           goto uncond;
+
+         if (!RELAX_BRANCH_LIKELY (fragp->fr_subtype))
+           {
+             /* Reverse the branch.  */
+             switch ((insn >> 28) & 0xf)
+               {
+               case 4:
+                 /* bc[0-3][tf]l? and bc1any[24][ft] instructions can
+                    have the condition reversed by tweaking a single
+                    bit, and their opcodes all have 0x4???????.  */
+                 assert ((insn & 0xf1000000) == 0x41000000);
+                 insn ^= 0x00010000;
+                 break;
+
+               case 0:
+                 /* bltz       0x04000000      bgez    0x04010000
+                    bltzal     0x04100000      bgezal  0x04110000 */
+                 assert ((insn & 0xfc0e0000) == 0x04000000);
+                 insn ^= 0x00010000;
+                 break;
+
+               case 1:
+                 /* beq        0x10000000      bne     0x14000000
+                    blez       0x18000000      bgtz    0x1c000000 */
+                 insn ^= 0x04000000;
+                 break;
+
+               default:
+                 abort ();
+               }
+           }
+
+         if (RELAX_BRANCH_LINK (fragp->fr_subtype))
+           {
+             /* Clear the and-link bit.  */
+             assert ((insn & 0xfc1c0000) == 0x04100000);
+
+             /* bltzal 0x04100000      bgezal  0x04110000
+               bltzall 0x04120000     bgezall  0x04130000 */
+             insn &= ~0x00100000;
+           }
+
+         /* Branch over the branch (if the branch was likely) or the
+            full jump (not likely case).  Compute the offset from the
+            current instruction to branch to.  */
+         if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
+           i = 16;
+         else
+           {
+             /* How many bytes in instructions we've already emitted?  */
+             i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
+             /* How many bytes in instructions from here to the end?  */
+             i = fragp->fr_var - i;
+           }
+         /* Convert to instruction count.  */
+         i >>= 2;
+         /* Branch counts from the next instruction.  */
+         i--;
+         insn |= i;
+         /* Branch over the jump.  */
+         md_number_to_chars ((char *)buf, insn, 4);
+         buf += 4;
+
+         /* Nop */
+         md_number_to_chars ((char*)buf, 0, 4);
+         buf += 4;
+
+         if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
+           {
+             /* beql $0, $0, 2f */
+             insn = 0x50000000;
+             /* Compute the PC offset from the current instruction to
+                the end of the variable frag.  */
+             /* How many bytes in instructions we've already emitted?  */
+             i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
+             /* How many bytes in instructions from here to the end?  */
+             i = fragp->fr_var - i;
+             /* Convert to instruction count.  */
+             i >>= 2;
+             /* Don't decrement i, because we want to branch over the
+                delay slot.  */
+
+             insn |= i;
+             md_number_to_chars ((char *)buf, insn, 4);
+             buf += 4;
+
+             md_number_to_chars ((char *)buf, 0, 4);
+             buf += 4;
+           }
+
+       uncond:
+         if (mips_pic == NO_PIC)
+           {
+             /* j or jal.  */
+             insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
+                     ? 0x0c000000 : 0x08000000);
+             exp.X_op = O_symbol;
+             exp.X_add_symbol = fragp->fr_symbol;
+             exp.X_add_number = fragp->fr_offset;
+
+             fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+                                 4, &exp, 0, BFD_RELOC_MIPS_JMP);
+             fixp->fx_file = fragp->fr_file;
+             fixp->fx_line = fragp->fr_line;
+
+             md_number_to_chars ((char*)buf, insn, 4);
+             buf += 4;
+           }
+         else
+           {
+             /* lw/ld $at, <sym>($gp)  R_MIPS_GOT16 */
+             insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
+             exp.X_op = O_symbol;
+             exp.X_add_symbol = fragp->fr_symbol;
+             exp.X_add_number = fragp->fr_offset;
+
+             if (fragp->fr_offset)
+               {
+                 exp.X_add_symbol = make_expr_symbol (&exp);
+                 exp.X_add_number = 0;
+               }
+
+             fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+                                 4, &exp, 0, BFD_RELOC_MIPS_GOT16);
+             fixp->fx_file = fragp->fr_file;
+             fixp->fx_line = fragp->fr_line;
+
+             md_number_to_chars ((char*)buf, insn, 4);
+             buf += 4;
+
+             if (mips_opts.isa == ISA_MIPS1)
+               {
+                 /* nop */
+                 md_number_to_chars ((char*)buf, 0, 4);
+                 buf += 4;
+               }
+
+             /* d/addiu $at, $at, <sym>  R_MIPS_LO16 */
+             insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
+
+             fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+                                 4, &exp, 0, BFD_RELOC_LO16);
+             fixp->fx_file = fragp->fr_file;
+             fixp->fx_line = fragp->fr_line;
+
+             md_number_to_chars ((char*)buf, insn, 4);
+             buf += 4;
+
+             /* j(al)r $at.  */
+             if (RELAX_BRANCH_LINK (fragp->fr_subtype))
+               insn = 0x0020f809;
+             else
+               insn = 0x00200008;
+
+             md_number_to_chars ((char*)buf, insn, 4);
+             buf += 4;
+           }
+       }
+
+      assert (buf == (bfd_byte *)fragp->fr_literal
+             + fragp->fr_fix + fragp->fr_var);
+
+      fragp->fr_fix += fragp->fr_var;
+
+      return;
+    }
+
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     {
       int type;
       register const struct mips16_immed_operand *op;
-      boolean small, ext;
+      bfd_boolean small, ext;
       offsetT val;
       bfd_byte *buf;
       unsigned long insn;
-      boolean use_extend;
+      bfd_boolean use_extend;
       unsigned short extend;
 
       type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
@@ -13019,13 +13807,13 @@ md_convert_frag (abfd, asec, fragp)
 
       if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
        {
-         small = false;
-         ext = true;
+         small = FALSE;
+         ext = TRUE;
        }
       else
        {
-         small = true;
-         ext = false;
+         small = TRUE;
+         ext = FALSE;
        }
 
       resolve_symbol_value (fragp->fr_symbol);
@@ -13170,7 +13958,7 @@ void
 mips_elf_final_processing ()
 {
   /* Write out the register information.  */
-  if (file_mips_abi != N64_ABI)
+  if (mips_abi != N64_ABI)
     {
       Elf32_RegInfo s;
 
@@ -13220,22 +14008,18 @@ mips_elf_final_processing ()
     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)
     {
-      /* Set the EABI kind based on the ISA.  This isn't really
-        the best, but then neither is basing the abi on the isa.  */
-      if (ISA_HAS_64BIT_REGS (file_mips_isa))
+      if (!file_mips_gp32)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
     }
-  else if (file_mips_abi == N32_ABI)
+  else if (mips_abi == N32_ABI)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
 
   /* Nothing to do for N64_ABI.  */
@@ -13366,13 +14150,30 @@ static void
 s_mips_file (x)
      int x ATTRIBUTE_UNUSED;
 {
+  static int first_file_directive = 0;
+
   if (ECOFF_DEBUGGING)
     {
       get_number ();
       s_app_file (0);
     }
   else
-    dwarf2_directive_file (0);
+    {
+      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.  */
@@ -13433,46 +14234,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 /* MIPS_STABS_ELF */
+      subseg_set (saved_seg, saved_subseg);
+    }
+#endif /* OBJ_ELF */
 
   cur_proc_ptr = NULL;
 }
@@ -13526,6 +14333,10 @@ s_mips_ent (aent)
       symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
 
       ++numprocs;
+
+      if (debug_type == DEBUG_STABS)
+        stabs_generate_asm_func (S_GET_NAME (symbolP),
+                                S_GET_NAME (symbolP));
     }
 
   demand_empty_rest_of_line ();
@@ -13541,36 +14352,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
@@ -13583,41 +14396,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;
+       }
 
-  off = get_absolute_expression ();
+      if (get_absolute_expression_and_terminator (&mask) != ',')
+       {
+         as_warn (_("Bad .mask/.fmask directive"));
+         --input_line_pointer;
+         demand_empty_rest_of_line ();
+         return;
+       }
 
-  if (reg_type == 'F')
-    {
-      cur_proc_ptr->fpreg_mask = mask;
-      cur_proc_ptr->fpreg_offset = off;
+      off = get_absolute_expression ();
+
+      if (reg_type == 'F')
+       {
+         cur_proc_ptr->fpreg_mask = mask;
+         cur_proc_ptr->fpreg_offset = off;
+       }
+      else
+       {
+         cur_proc_ptr->reg_mask = mask;
+         cur_proc_ptr->reg_offset = off;
+       }
+
+      demand_empty_rest_of_line ();
     }
   else
-    {
-      cur_proc_ptr->reg_mask = mask;
-      cur_proc_ptr->reg_offset = off;
-    }
-
-  demand_empty_rest_of_line ();
-#else
-  s_ignore (reg_type);
-#endif /* MIPS_STABS_ELF */
+#endif /* OBJ_ELF */
+    s_ignore (reg_type);
 }
 
 /* The .loc directive.  */
@@ -13644,176 +14460,181 @@ 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 },
+  { "mips32r2",       1,      ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "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 },
+  { "vr4120",         0,      ISA_MIPS3,      CPU_VR4120 },
+  { "vr4130",         0,      ISA_MIPS3,      CPU_VR4120 },
+  { "vr4181",         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 },
+  { "vr5400",         0,      ISA_MIPS4,      CPU_VR5400 },
+  { "vr5500",         0,      ISA_MIPS4,      CPU_VR5500 },
+  { "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 },
+
+  /* MIPS 64 */
+  { "5kc",            0,      ISA_MIPS64,     CPU_MIPS64 },
+  { "20kc",           0,      ISA_MIPS64,     CPU_MIPS64 },
+
+  /* Broadcom SB-1 CPU core */
+  { "sb1",            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 bfd_boolean
+mips_strict_matching_cpu_name_p (canonical, given)
+     const char *canonical, *given;
+{
+  while (*given != 0 && TOLOWER (*given) == TOLOWER (*canonical))
+    given++, canonical++;
 
-  /* MIPS2 ISA */
-  { "MIPS2",          1,      ISA_MIPS2,      CPU_R6000, },
+  return ((*given == 0 && *canonical == 0)
+         || (strcmp (canonical, "000") == 0 && strcasecmp (given, "k") == 0));
+}
 
-  /* MIPS3 ISA */
-  { "MIPS3",          1,      ISA_MIPS3,      CPU_R4000, },
 
-  /* MIPS4 ISA */
-  { "MIPS4",          1,      ISA_MIPS4,      CPU_R8000, },
+/* Return true if GIVEN matches CANONICAL, where GIVEN is a user-supplied
+   CPU name.  We've traditionally allowed a lot of variation here.
 
-  /* MIPS5 ISA */
-  { "MIPS5",          1,      ISA_MIPS5,      CPU_MIPS5, },
-  { "Generic-MIPS5",  0,      ISA_MIPS5,      CPU_MIPS5, },
+   Note: this function is shared between GCC and GAS.  */
 
-  /* 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, },
-};
+static bfd_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;
@@ -13822,22 +14643,129 @@ 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\
+-mips32r2               generate MIPS32 release 2 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
+}
+
+enum dwarf2_format
+mips_dwarf2_format ()
+{
+  if (mips_abi == N64_ABI)
+    return dwarf2_format_64bit_irix;
+  else
+    return dwarf2_format_32bit;
 }
This page took 0.109922 seconds and 4 git commands to generate.