gas/
[external/binutils.git] / gas / config / tc-mips.c
index 50e5024..4e878c8 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 
+/* Check assumptions made in this file.  */
+typedef char static_assert1[sizeof (offsetT) < 8 ? -1 : 1];
+typedef char static_assert2[sizeof (valueT) < 8 ? -1 : 1];
+
 #ifdef DEBUG
 #define DBG(x) printf x
 #else
 #define DBG(x)
 #endif
 
-#ifdef OBJ_MAYBE_ELF
 /* Clean up namespace so we can include obj-elf.h too.  */
 static int mips_output_flavor (void);
 static int mips_output_flavor (void) { return OUTPUT_FLAVOR; }
@@ -61,11 +64,8 @@ static int mips_output_flavor (void) { return OUTPUT_FLAVOR; }
 /* Fix any of them that we actually care about.  */
 #undef OUTPUT_FLAVOR
 #define OUTPUT_FLAVOR mips_output_flavor()
-#endif
 
-#if defined (OBJ_ELF)
 #include "elf/mips.h"
-#endif
 
 #ifndef ECOFF_DEBUGGING
 #define NO_ECOFF_DEBUGGING
@@ -85,9 +85,7 @@ int mips_flag_pdr = TRUE;
 
 #include "ecoff.h"
 
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 static char *mips_regmask_frag;
-#endif
 
 #define ZERO 0
 #define ATREG 1
@@ -106,22 +104,10 @@ static char *mips_regmask_frag;
 
 #define AT  mips_opts.at
 
-/* Allow override of standard little-endian ECOFF format.  */
-
-#ifndef ECOFF_LITTLE_FORMAT
-#define ECOFF_LITTLE_FORMAT "ecoff-littlemips"
-#endif
-
 extern int target_big_endian;
 
 /* The name of the readonly data section.  */
-#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
-                           ? ".rdata" \
-                           : OUTPUT_FLAVOR == bfd_target_coff_flavour \
-                           ? ".rdata" \
-                           : OUTPUT_FLAVOR == bfd_target_elf_flavour \
-                           ? ".rodata" \
-                           : (abort (), ""))
+#define RDATA_SECTION_NAME ".rodata"
 
 /* Ways in which an instruction can be "appended" to the output.  */
 enum append_method {
@@ -145,15 +131,10 @@ struct mips_cl_insn
   /* The opcode's entry in mips_opcodes or mips16_opcodes.  */
   const struct mips_opcode *insn_mo;
 
-  /* True if this is a mips16 instruction and if we want the extended
-     form of INSN_MO.  */
-  bfd_boolean use_extend;
-
-  /* The 16-bit extension instruction to use when USE_EXTEND is true.  */
-  unsigned short extend;
-
   /* The 16-bit or 32-bit bitstring of the instruction itself.  This is
-     a copy of INSN_MO->match with the operands filled in.  */
+     a copy of INSN_MO->match with the operands filled in.  If we have
+     decided to use an extended MIPS16 instruction, this includes the
+     extension.  */
   unsigned long insn_opcode;
 
   /* The frag that contains the instruction.  */
@@ -176,6 +157,10 @@ struct mips_cl_insn
 
   /* True if this instruction is complete.  */
   unsigned int complete_p : 1;
+
+  /* True if this instruction is cleared from history by unconditional
+     branch.  */
+  unsigned int cleared_p : 1;
 };
 
 /* The ABI to use.  */
@@ -209,16 +194,10 @@ struct mips_set_options
      if it has not been initialized.  Changed by `.set mipsN', and the
      -mipsN command line option, and the default CPU.  */
   int isa;
-  /* Enabled Application Specific Extensions (ASEs).  These are set to -1
-     if they have not been initialized.  Changed by `.set <asename>', by
-     command line options, and based on the default architecture.  */
-  int ase_mips3d;
-  int ase_mdmx;
-  int ase_smartmips;
-  int ase_dsp;
-  int ase_dspr2;
-  int ase_mt;
-  int ase_mcu;
+  /* Enabled Application Specific Extensions (ASEs).  Changed by `.set
+     <asename>', by command line options, and based on the default
+     architecture.  */
+  int ase;
   /* Whether we are assembling for the mips16 processor.  0 if we are
      not, 1 if we are, and -1 if the value has not been initialized.
      Changed by `.set mips16' and `.set nomips16', and the -mips16 and
@@ -252,6 +231,10 @@ struct mips_set_options
   /* Non-zero if we should not autoextend mips16 instructions.
      Changed by `.set autoextend' and `.set noautoextend'.  */
   int noautoextend;
+  /* True if we should only emit 32-bit microMIPS instructions.
+     Changed by `.set insn32' and `.set noinsn32', and the -minsn32
+     and -mno-insn32 command line options.  */
+  bfd_boolean insn32;
   /* Restrict general purpose registers and floating point registers
      to 32 bit.  This is initially determined when -mgp32 or -mfp32
      is passed but can changed if the assembler code uses .set mipsN.  */
@@ -289,16 +272,25 @@ static int file_mips_soft_float = 0;
 /* 1 if -msingle-float, 0 if -mdouble-float.  The default is 0.   */
 static int file_mips_single_float = 0;
 
+/* True if -mnan=2008, false if -mnan=legacy.  */
+static bfd_boolean mips_flag_nan2008 = FALSE;
+
 static struct mips_set_options mips_opts =
 {
-  /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
-  /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
-  /* ase_mcu */ -1, /* mips16 */ -1, /* micromips */ -1, /* noreorder */ 0,
-  /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
-  /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
-  /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
+  /* isa */ ISA_UNKNOWN, /* ase */ 0, /* mips16 */ -1, /* micromips */ -1,
+  /* noreorder */ 0,  /* at */ ATREG, /* warn_about_macros */ 0,
+  /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
+  /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+  /* soft_float */ FALSE, /* single_float */ FALSE
 };
 
+/* The set of ASEs that were selected on the command line, either
+   explicitly via ASE options or implicitly through things like -march.  */
+static unsigned int file_ase;
+
+/* Which bits of file_ase were explicitly set or cleared by ASE options.  */
+static unsigned int file_ase_explicit;
+
 /* These variables are filled in with the masks of registers used.
    The object format code reads them and puts them in the appropriate
    place.  */
@@ -331,48 +323,6 @@ static int file_ase_micromips;
    || ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
 #endif
 
-/* True if -mips3d was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_mips3d;
-
-/* True if -mdmx was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_mdmx;
-
-/* True if -msmartmips was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_smartmips;
-
-#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32            \
-                               || mips_opts.isa == ISA_MIPS32R2)
-
-/* True if -mdsp was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_dsp;
-
-#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2            \
-                             || mips_opts.isa == ISA_MIPS64R2)
-
-#define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
-
-/* True if -mdspr2 was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_dspr2;
-
-#define ISA_SUPPORTS_DSPR2_ASE (mips_opts.isa == ISA_MIPS32R2          \
-                               || mips_opts.isa == ISA_MIPS64R2)
-
-/* True if -mmt was passed or implied by arguments passed on the
-   command line (e.g., by -march).  */
-static int file_ase_mt;
-
-#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2             \
-                            || mips_opts.isa == ISA_MIPS64R2)
-
-#define ISA_SUPPORTS_MCU_ASE (mips_opts.isa == ISA_MIPS32R2            \
-                             || mips_opts.isa == ISA_MIPS64R2          \
-                             || mips_opts.micromips)
-
 /* The argument of the -march= flag.  The architecture we are assembling.  */
 static int file_mips_arch = CPU_UNKNOWN;
 static const char *mips_arch_string;
@@ -424,7 +374,7 @@ static int mips_32bitmode = 0;
 #define ISA_HAS_ROR(ISA)               \
   ((ISA) == ISA_MIPS32R2               \
    || (ISA) == ISA_MIPS64R2            \
-   || mips_opts.ase_smartmips          \
+   || (mips_opts.ase & ASE_SMARTMIPS)  \
    || mips_opts.micromips              \
    )
 
@@ -503,10 +453,9 @@ static int mips_32bitmode = 0;
 /* True if CPU has seq/sne and seqi/snei instructions.  */
 #define CPU_HAS_SEQ(CPU)       (CPU_IS_OCTEON (CPU))
 
-/* True if CPU does not implement the all the coprocessor insns.  For these
-   CPUs only those COP insns are accepted that are explicitly marked to be
-   available on the CPU.  ISA membership for COP insns is ignored.  */
-#define NO_ISA_COP(CPU)                (CPU_IS_OCTEON (CPU))
+/* True, if CPU has support for ldc1 and sdc1. */
+#define CPU_HAS_LDC1_SDC1(CPU) \
+   ((mips_opts.isa != ISA_MIPS1) && ((CPU) != CPU_R5900))
 
 /* True if mflo and mfhi can be immediately followed by instructions
    which write to the HI and LO registers.
@@ -526,6 +475,7 @@ static int mips_32bitmode = 0;
    || mips_opts.isa == ISA_MIPS64                     \
    || mips_opts.isa == ISA_MIPS64R2                   \
    || mips_opts.arch == CPU_R4010                     \
+   || mips_opts.arch == CPU_R5900                     \
    || mips_opts.arch == CPU_R10000                    \
    || mips_opts.arch == CPU_R12000                    \
    || mips_opts.arch == CPU_R14000                    \
@@ -543,6 +493,7 @@ static int mips_32bitmode = 0;
 #define gpr_interlocks                                \
   (mips_opts.isa != ISA_MIPS1                         \
    || mips_opts.arch == CPU_R3900                     \
+   || mips_opts.arch == CPU_R5900                     \
    || mips_opts.micromips                             \
    )
 
@@ -578,21 +529,16 @@ static int mips_32bitmode = 0;
 #define MF_HILO_INSN(PINFO) \
   ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
 
-/* Returns true for a (non floating-point) coprocessor instruction.  Reading
-   or writing the condition code is only possible on the coprocessors and
-   these insns are not marked with INSN_COP.  Thus for these insns use the
-   condition-code flags.  */
-#define COP_INSN(PINFO)                                                        \
-  (PINFO != INSN_MACRO                                                 \
-   && ((PINFO) & (FP_S | FP_D)) == 0                                   \
-   && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
-
 /* Whether code compression (either of the MIPS16 or the microMIPS ASEs)
    has been selected.  This implies, in particular, that addresses of text
    labels have their LSB set.  */
 #define HAVE_CODE_COMPRESSION                                          \
   ((mips_opts.mips16 | mips_opts.micromips) != 0)
 
+/* The minimum and maximum signed values that can be stored in a GPR.  */
+#define GPR_SMAX ((offsetT) (((valueT) 1 << (HAVE_64BIT_GPRS ? 63 : 31)) - 1))
+#define GPR_SMIN (-GPR_SMAX - 1)
+
 /* MIPS PIC level.  */
 
 enum mips_pic_level mips_pic;
@@ -747,11 +693,18 @@ static struct mips_cl_insn micromips_nop16_insn;
 static struct mips_cl_insn micromips_nop32_insn;
 
 /* The appropriate nop for the current mode.  */
-#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn \
-                 : (mips_opts.micromips ? &micromips_nop16_insn : &nop_insn))
+#define NOP_INSN (mips_opts.mips16                                     \
+                 ? &mips16_nop_insn                                    \
+                 : (mips_opts.micromips                                \
+                    ? (mips_opts.insn32                                \
+                       ? &micromips_nop32_insn                         \
+                       : &micromips_nop16_insn)                        \
+                    : &nop_insn))
 
 /* The size of NOP_INSN in bytes.  */
-#define NOP_INSN_SIZE (HAVE_CODE_COMPRESSION ? 2 : 4)
+#define NOP_INSN_SIZE ((mips_opts.mips16                               \
+                       || (mips_opts.micromips && !mips_opts.insn32))  \
+                      ? 2 : 4)
 
 /* If this is set, it points to a frag holding nop instructions which
    were inserted before the start of a noreorder section.  If those
@@ -769,12 +722,12 @@ static int prev_nop_frag_required;
 /* The number of instructions we've seen since prev_nop_frag.  */
 static int prev_nop_frag_since;
 
-/* For ECOFF and ELF, relocations against symbols are done in two
-   parts, with a HI relocation and a LO relocation.  Each relocation
-   has only 16 bits of space to store an addend.  This means that in
-   order for the linker to handle carries correctly, it must be able
-   to locate both the HI and the LO relocation.  This means that the
-   relocations must appear in order in the relocation table.
+/* Relocations against symbols are sometimes done in two parts, with a HI
+   relocation and a LO relocation.  Each relocation has only 16 bits of
+   space to store an addend.  This means that in order for the linker to
+   handle carries correctly, it must be able to locate both the HI and
+   the LO relocation.  This means that the relocations must appear in
+   order in the relocation table.
 
    In order to implement this, we keep track of each unmatched HI
    relocation.  We then sort them so that they immediately precede the
@@ -829,15 +782,6 @@ static const unsigned int mips16_to_32_reg_map[] =
 #define mips32_to_micromips_reg_l_map  mips32_to_16_reg_map
 
 #define X ILLEGAL_REG
-/* reg type h: 4, 5, 6.  */
-static const int mips32_to_micromips_reg_h_map[] =
-{
-  X, X, X, X, 4, 5, 6, X,
-  X, X, X, X, X, X, X, X,
-  X, X, X, X, X, X, X, X,
-  X, X, X, X, X, X, X, X
-};
-
 /* reg type m: 0, 17, 2, 3, 16, 18, 19, 20.  */
 static const int mips32_to_micromips_reg_m_map[] =
 {
@@ -869,13 +813,11 @@ static const int mips32_to_micromips_reg_q_map[] =
 #define micromips_to_32_reg_g_map      mips16_to_32_reg_map
 
 /* The microMIPS registers with type h.  */
-static const unsigned int micromips_to_32_reg_h_map[] =
+static const unsigned int micromips_to_32_reg_h_map1[] =
 {
   5, 5, 6, 4, 4, 4, 4, 4
 };
-
-/* The microMIPS registers with type i.  */
-static const unsigned int micromips_to_32_reg_i_map[] =
+static const unsigned int micromips_to_32_reg_h_map2[] =
 {
   6, 7, 7, 21, 22, 5, 6, 7
 };
@@ -1193,6 +1135,9 @@ static int mips_relax_branch;
 #define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x40000)
 #define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x40000)
 
+/* Sign-extend 16-bit value X.  */
+#define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000)
+
 /* Is the given value a sign-extended 32-bit value?  */
 #define IS_SEXT_32BIT_NUM(x)                                           \
   (((x) &~ (offsetT) 0x7fffffff) == 0                                  \
@@ -1207,6 +1152,10 @@ static int mips_relax_branch;
 #define IS_SEXT_12BIT_NUM(x)                                           \
   (((((x) & 0xfff) ^ 0x800LL) - 0x800LL) == (x))
 
+/* Is the given value a sign-extended 9-bit value?  */
+#define IS_SEXT_9BIT_NUM(x)                                            \
+  (((((x) & 0x1ff) ^ 0x100LL) - 0x100LL) == (x))
+
 /* Is the given value a zero-extended 32-bit value?  Or a negated one?  */
 #define IS_ZEXT_32BIT_NUM(x)                                           \
   (((x) &~ (offsetT) 0xffffffff) == 0                                  \
@@ -1252,6 +1201,9 @@ static int mips_relax_branch;
   EXTRACT_BITS ((INSN).insn_opcode, \
                MIPS16OP_MASK_##FIELD, \
                MIPS16OP_SH_##FIELD)
+
+/* The MIPS16 EXTEND opcode, shifted left 16 places.  */
+#define MIPS16_EXTEND (0xf000U << 16)
 \f
 /* Whether or not we are emitting a branch-likely macro.  */
 static bfd_boolean emit_branch_likely_macro = FALSE;
@@ -1315,9 +1267,6 @@ static struct {
 \f
 /* Prototypes for static functions.  */
 
-#define internalError()                                                        \
-    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
-
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
@@ -1330,13 +1279,13 @@ static void mips16_macro_build
 static void load_register (int, expressionS *, int);
 static void macro_start (void);
 static void macro_end (void);
-static void macro (struct mips_cl_insn * ip);
+static void macro (struct mips_cl_insn *ip, char *str);
 static void mips16_macro (struct mips_cl_insn * ip);
 static void mips_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_ip (char *str, struct mips_cl_insn * ip);
 static void mips16_immed
-  (char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean, bfd_boolean,
-   unsigned long *, bfd_boolean *, unsigned short *);
+  (char *, unsigned int, int, bfd_reloc_code_real_type, offsetT,
+   unsigned int, unsigned long *);
 static size_t my_getSmallExpression
   (expressionS *, bfd_reloc_code_real_type *, char *);
 static void my_getExpression (expressionS *, char *);
@@ -1356,11 +1305,15 @@ static void s_cprestore (int);
 static void s_cpreturn (int);
 static void s_dtprelword (int);
 static void s_dtpreldword (int);
+static void s_tprelword (int);
+static void s_tpreldword (int);
 static void s_gpvalue (int);
 static void s_gpword (int);
 static void s_gpdword (int);
+static void s_ehword (int);
 static void s_cpadd (int);
 static void s_insn (int);
+static void s_nan (int);
 static void md_obj_begin (void);
 static void md_obj_end (void);
 static void s_mips_ent (int);
@@ -1384,24 +1337,314 @@ static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
 struct mips_cpu_info
 {
   const char *name;           /* CPU or ISA name.  */
-  int flags;                  /* ASEs available, or ISA flag.  */
+  int flags;                  /* MIPS_CPU_* flags.  */
+  int ase;                    /* Set of ASEs implemented by the CPU.  */
   int isa;                    /* ISA level.  */
   int cpu;                    /* CPU number (default CPU if ISA).  */
 };
 
 #define MIPS_CPU_IS_ISA                0x0001  /* Is this an ISA?  (If 0, a CPU.) */
-#define MIPS_CPU_ASE_SMARTMIPS 0x0002  /* CPU implements SmartMIPS ASE */
-#define MIPS_CPU_ASE_DSP       0x0004  /* CPU implements DSP ASE */
-#define MIPS_CPU_ASE_MT                0x0008  /* CPU implements MT ASE */
-#define MIPS_CPU_ASE_MIPS3D    0x0010  /* CPU implements MIPS-3D ASE */
-#define MIPS_CPU_ASE_MDMX      0x0020  /* CPU implements MDMX ASE */
-#define MIPS_CPU_ASE_DSPR2     0x0040  /* CPU implements DSP R2 ASE */
-#define MIPS_CPU_ASE_MCU       0x0080  /* CPU implements MCU ASE */
 
 static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
 static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
 static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
 \f
+/* Command-line options.  */
+const char *md_shortopts = "O::g::G:";
+
+enum options
+  {
+    OPTION_MARCH = OPTION_MD_BASE,
+    OPTION_MTUNE,
+    OPTION_MIPS1,
+    OPTION_MIPS2,
+    OPTION_MIPS3,
+    OPTION_MIPS4,
+    OPTION_MIPS5,
+    OPTION_MIPS32,
+    OPTION_MIPS64,
+    OPTION_MIPS32R2,
+    OPTION_MIPS64R2,
+    OPTION_MIPS16,
+    OPTION_NO_MIPS16,
+    OPTION_MIPS3D,
+    OPTION_NO_MIPS3D,
+    OPTION_MDMX,
+    OPTION_NO_MDMX,
+    OPTION_DSP,
+    OPTION_NO_DSP,
+    OPTION_MT,
+    OPTION_NO_MT,
+    OPTION_VIRT,
+    OPTION_NO_VIRT,
+    OPTION_SMARTMIPS,
+    OPTION_NO_SMARTMIPS,
+    OPTION_DSPR2,
+    OPTION_NO_DSPR2,
+    OPTION_EVA,
+    OPTION_NO_EVA,
+    OPTION_MICROMIPS,
+    OPTION_NO_MICROMIPS,
+    OPTION_MCU,
+    OPTION_NO_MCU,
+    OPTION_COMPAT_ARCH_BASE,
+    OPTION_M4650,
+    OPTION_NO_M4650,
+    OPTION_M4010,
+    OPTION_NO_M4010,
+    OPTION_M4100,
+    OPTION_NO_M4100,
+    OPTION_M3900,
+    OPTION_NO_M3900,
+    OPTION_M7000_HILO_FIX,
+    OPTION_MNO_7000_HILO_FIX,
+    OPTION_FIX_24K,
+    OPTION_NO_FIX_24K,
+    OPTION_FIX_LOONGSON2F_JUMP,
+    OPTION_NO_FIX_LOONGSON2F_JUMP,
+    OPTION_FIX_LOONGSON2F_NOP,
+    OPTION_NO_FIX_LOONGSON2F_NOP,
+    OPTION_FIX_VR4120,
+    OPTION_NO_FIX_VR4120,
+    OPTION_FIX_VR4130,
+    OPTION_NO_FIX_VR4130,
+    OPTION_FIX_CN63XXP1,
+    OPTION_NO_FIX_CN63XXP1,
+    OPTION_TRAP,
+    OPTION_BREAK,
+    OPTION_EB,
+    OPTION_EL,
+    OPTION_FP32,
+    OPTION_GP32,
+    OPTION_CONSTRUCT_FLOATS,
+    OPTION_NO_CONSTRUCT_FLOATS,
+    OPTION_FP64,
+    OPTION_GP64,
+    OPTION_RELAX_BRANCH,
+    OPTION_NO_RELAX_BRANCH,
+    OPTION_INSN32,
+    OPTION_NO_INSN32,
+    OPTION_MSHARED,
+    OPTION_MNO_SHARED,
+    OPTION_MSYM32,
+    OPTION_MNO_SYM32,
+    OPTION_SOFT_FLOAT,
+    OPTION_HARD_FLOAT,
+    OPTION_SINGLE_FLOAT,
+    OPTION_DOUBLE_FLOAT,
+    OPTION_32,
+    OPTION_CALL_SHARED,
+    OPTION_CALL_NONPIC,
+    OPTION_NON_SHARED,
+    OPTION_XGOT,
+    OPTION_MABI,
+    OPTION_N32,
+    OPTION_64,
+    OPTION_MDEBUG,
+    OPTION_NO_MDEBUG,
+    OPTION_PDR,
+    OPTION_NO_PDR,
+    OPTION_MVXWORKS_PIC,
+    OPTION_NAN,
+    OPTION_END_OF_ENUM
+  };
+
+struct option md_longopts[] =
+{
+  /* Options which specify architecture.  */
+  {"march", required_argument, NULL, OPTION_MARCH},
+  {"mtune", required_argument, NULL, OPTION_MTUNE},
+  {"mips0", no_argument, NULL, OPTION_MIPS1},
+  {"mips1", no_argument, NULL, OPTION_MIPS1},
+  {"mips2", no_argument, NULL, OPTION_MIPS2},
+  {"mips3", no_argument, NULL, OPTION_MIPS3},
+  {"mips4", no_argument, NULL, OPTION_MIPS4},
+  {"mips5", no_argument, NULL, OPTION_MIPS5},
+  {"mips32", no_argument, NULL, OPTION_MIPS32},
+  {"mips64", no_argument, NULL, OPTION_MIPS64},
+  {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
+  {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
+
+  /* Options which specify Application Specific Extensions (ASEs).  */
+  {"mips16", no_argument, NULL, OPTION_MIPS16},
+  {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
+  {"mips3d", no_argument, NULL, OPTION_MIPS3D},
+  {"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
+  {"mdmx", no_argument, NULL, OPTION_MDMX},
+  {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
+  {"mdsp", no_argument, NULL, OPTION_DSP},
+  {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
+  {"mmt", no_argument, NULL, OPTION_MT},
+  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
+  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
+  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
+  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
+  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
+  {"meva", no_argument, NULL, OPTION_EVA},
+  {"mno-eva", no_argument, NULL, OPTION_NO_EVA},
+  {"mmicromips", no_argument, NULL, OPTION_MICROMIPS},
+  {"mno-micromips", no_argument, NULL, OPTION_NO_MICROMIPS},
+  {"mmcu", no_argument, NULL, OPTION_MCU},
+  {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
+  {"mvirt", no_argument, NULL, OPTION_VIRT},
+  {"mno-virt", no_argument, NULL, OPTION_NO_VIRT},
+
+  /* Old-style architecture options.  Don't add more of these.  */
+  {"m4650", no_argument, NULL, OPTION_M4650},
+  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
+  {"m4010", no_argument, NULL, OPTION_M4010},
+  {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
+  {"m4100", no_argument, NULL, OPTION_M4100},
+  {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
+  {"m3900", no_argument, NULL, OPTION_M3900},
+  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
+
+  /* Options which enable bug fixes.  */
+  {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
+  {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+  {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+  {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+  {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
+  {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
+  {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
+  {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
+  {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
+  {"mfix-24k",    no_argument, NULL, OPTION_FIX_24K},
+  {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
+  {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
+  {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
+
+  /* Miscellaneous options.  */
+  {"trap", no_argument, NULL, OPTION_TRAP},
+  {"no-break", no_argument, NULL, OPTION_TRAP},
+  {"break", no_argument, NULL, OPTION_BREAK},
+  {"no-trap", no_argument, NULL, OPTION_BREAK},
+  {"EB", no_argument, NULL, OPTION_EB},
+  {"EL", no_argument, NULL, OPTION_EL},
+  {"mfp32", no_argument, NULL, OPTION_FP32},
+  {"mgp32", no_argument, NULL, OPTION_GP32},
+  {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
+  {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
+  {"mfp64", no_argument, NULL, OPTION_FP64},
+  {"mgp64", no_argument, NULL, OPTION_GP64},
+  {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
+  {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
+  {"minsn32", no_argument, NULL, OPTION_INSN32},
+  {"mno-insn32", no_argument, NULL, OPTION_NO_INSN32},
+  {"mshared", no_argument, NULL, OPTION_MSHARED},
+  {"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
+  {"msym32", no_argument, NULL, OPTION_MSYM32},
+  {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
+  {"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
+  {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
+  {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
+  {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+
+  /* Strictly speaking this next option is ELF specific,
+     but we allow it for other ports as well in order to
+     make testing easier.  */
+  {"32", no_argument, NULL, OPTION_32},
+
+  /* ELF-specific options.  */
+  {"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
+  {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
+  {"call_nonpic", no_argument, NULL, OPTION_CALL_NONPIC},
+  {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
+  {"xgot", no_argument, NULL, OPTION_XGOT},
+  {"mabi", required_argument, NULL, OPTION_MABI},
+  {"n32", no_argument, NULL, OPTION_N32},
+  {"64", no_argument, NULL, OPTION_64},
+  {"mdebug", no_argument, NULL, OPTION_MDEBUG},
+  {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
+  {"mpdr", no_argument, NULL, OPTION_PDR},
+  {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
+  {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
+  {"mnan", required_argument, NULL, OPTION_NAN},
+
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+\f
+/* Information about either an Application Specific Extension or an
+   optional architecture feature that, for simplicity, we treat in the
+   same way as an ASE.  */
+struct mips_ase
+{
+  /* The name of the ASE, used in both the command-line and .set options.  */
+  const char *name;
+
+  /* The associated ASE_* flags.  If the ASE is available on both 32-bit
+     and 64-bit architectures, the flags here refer to the subset that
+     is available on both.  */
+  unsigned int flags;
+
+  /* The ASE_* flag used for instructions that are available on 64-bit
+     architectures but that are not included in FLAGS.  */
+  unsigned int flags64;
+
+  /* The command-line options that turn the ASE on and off.  */
+  int option_on;
+  int option_off;
+
+  /* The minimum required architecture revisions for MIPS32, MIPS64,
+     microMIPS32 and microMIPS64, or -1 if the extension isn't supported.  */
+  int mips32_rev;
+  int mips64_rev;
+  int micromips32_rev;
+  int micromips64_rev;
+};
+
+/* A table of all supported ASEs.  */
+static const struct mips_ase mips_ases[] = {
+  { "dsp", ASE_DSP, ASE_DSP64,
+    OPTION_DSP, OPTION_NO_DSP,
+    2, 2, 2, 2 },
+
+  { "dspr2", ASE_DSP | ASE_DSPR2, 0,
+    OPTION_DSPR2, OPTION_NO_DSPR2,
+    2, 2, 2, 2 },
+
+  { "eva", ASE_EVA, 0,
+    OPTION_EVA, OPTION_NO_EVA,
+    2, 2, 2, 2 },
+
+  { "mcu", ASE_MCU, 0,
+    OPTION_MCU, OPTION_NO_MCU,
+    2, 2, 2, 2 },
+
+  /* Deprecated in MIPS64r5, but we don't implement that yet.  */
+  { "mdmx", ASE_MDMX, 0,
+    OPTION_MDMX, OPTION_NO_MDMX,
+    -1, 1, -1, -1 },
+
+  /* Requires 64-bit FPRs, so the minimum MIPS32 revision is 2.  */
+  { "mips3d", ASE_MIPS3D, 0,
+    OPTION_MIPS3D, OPTION_NO_MIPS3D,
+    2, 1, -1, -1 },
+
+  { "mt", ASE_MT, 0,
+    OPTION_MT, OPTION_NO_MT,
+    2, 2, -1, -1 },
+
+  { "smartmips", ASE_SMARTMIPS, 0,
+    OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS,
+    1, -1, -1, -1 },
+
+  { "virt", ASE_VIRT, ASE_VIRT64,
+    OPTION_VIRT, OPTION_NO_VIRT,
+    2, 2, 2, 2 }
+};
+
+/* The set of ASEs that require -mfp64.  */
+#define FP64_ASES (ASE_MIPS3D | ASE_MDMX)
+
+/* Groups of ASE_* flags that represent different revisions of an ASE.  */
+static const unsigned int mips_ase_groups[] = {
+  ASE_DSP | ASE_DSPR2
+};
+\f
 /* Pseudo-op table.
 
    The following pseudo-ops from the Kane and Heinrich MIPS book
@@ -1435,11 +1678,15 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpreturn", s_cpreturn, 0},
   {"dtprelword", s_dtprelword, 0},
   {"dtpreldword", s_dtpreldword, 0},
+  {"tprelword", s_tprelword, 0},
+  {"tpreldword", s_tpreldword, 0},
   {"gpvalue", s_gpvalue, 0},
   {"gpword", s_gpword, 0},
   {"gpdword", s_gpdword, 0},
+  {"ehword", s_ehword, 0},
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
+  {"nan", s_nan, 0},
 
   /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
@@ -1472,7 +1719,9 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"section", s_change_section, 0},
   {"short", s_cons, 1},
   {"single", s_float_cons, 'f'},
+  {"stabd", s_mips_stab, 'd'},
   {"stabn", s_mips_stab, 'n'},
+  {"stabs", s_mips_stab, 's'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
 
@@ -1561,17 +1810,18 @@ mips_mark_labels (void)
 \f
 static char *expr_end;
 
-/* Expressions which appear in instructions.  These are set by
-   mips_ip.  */
+/* Expressions which appear in macro instructions.  These are set by
+   mips_ip and read by macro.  */
 
 static expressionS imm_expr;
 static expressionS imm2_expr;
-static expressionS offset_expr;
 
-/* Relocs associated with imm_expr and offset_expr.  */
+/* The relocatable field in an instruction and the relocs associated
+   with it.  These variables are used for instructions like LUI and
+   JAL as well as true offsets.  They are also used for address
+   operands in macros.  */
 
-static bfd_reloc_code_real_type imm_reloc[3]
-  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
+static expressionS offset_expr;
 static bfd_reloc_code_real_type offset_reloc[3]
   = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
@@ -1581,12 +1831,15 @@ static bfd_reloc_code_real_type offset_reloc[3]
 
 static unsigned int forced_insn_length;
 
-#ifdef OBJ_ELF
+/* True if we are assembling an instruction.  All dot symbols defined during
+   this time should be treated as code labels.  */
+
+static bfd_boolean mips_assembling_insn;
+
 /* The pdr segment for per procedure frame/regmask info.  Not used for
    ECOFF debugging.  */
 
 static segT pdr_seg;
-#endif
 
 /* The default target format to use.  */
 
@@ -1603,10 +1856,6 @@ mips_target_format (void)
 {
   switch (OUTPUT_FLAVOR)
     {
-    case bfd_target_ecoff_flavour:
-      return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
-    case bfd_target_coff_flavour:
-      return "pe-mips";
     case bfd_target_elf_flavour:
 #ifdef TE_VXWORKS
       if (!HAVE_64BIT_OBJECTS && !HAVE_NEWABI)
@@ -1631,11 +1880,124 @@ mips_target_format (void)
     }
 }
 
-/* Return the length of a microMIPS instruction in bytes.  If bits of
-   the mask beyond the low 16 are 0, then it is a 16-bit instruction.
-   Otherwise assume a 32-bit instruction; 48-bit instructions (0x1f
-   major opcode) will require further modifications to the opcode
-   table.  */
+/* Return the ISA revision that is currently in use, or 0 if we are
+   generating code for MIPS V or below.  */
+
+static int
+mips_isa_rev (void)
+{
+  if (mips_opts.isa == ISA_MIPS32R2 || mips_opts.isa == ISA_MIPS64R2)
+    return 2;
+
+  /* microMIPS implies revision 2 or above.  */
+  if (mips_opts.micromips)
+    return 2;
+
+  if (mips_opts.isa == ISA_MIPS32 || mips_opts.isa == ISA_MIPS64)
+    return 1;
+
+  return 0;
+}
+
+/* Return the mask of all ASEs that are revisions of those in FLAGS.  */
+
+static unsigned int
+mips_ase_mask (unsigned int flags)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (mips_ase_groups); i++)
+    if (flags & mips_ase_groups[i])
+      flags |= mips_ase_groups[i];
+  return flags;
+}
+
+/* Check whether the current ISA supports ASE.  Issue a warning if
+   appropriate.  */
+
+static void
+mips_check_isa_supports_ase (const struct mips_ase *ase)
+{
+  const char *base;
+  int min_rev, size;
+  static unsigned int warned_isa;
+  static unsigned int warned_fp32;
+
+  if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+    min_rev = mips_opts.micromips ? ase->micromips64_rev : ase->mips64_rev;
+  else
+    min_rev = mips_opts.micromips ? ase->micromips32_rev : ase->mips32_rev;
+  if ((min_rev < 0 || mips_isa_rev () < min_rev)
+      && (warned_isa & ase->flags) != ase->flags)
+    {
+      warned_isa |= ase->flags;
+      base = mips_opts.micromips ? "microMIPS" : "MIPS";
+      size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
+      if (min_rev < 0)
+       as_warn (_("The %d-bit %s architecture does not support the"
+                  " `%s' extension"), size, base, ase->name);
+      else
+       as_warn (_("The `%s' extension requires %s%d revision %d or greater"),
+                ase->name, base, size, min_rev);
+    }
+  if ((ase->flags & FP64_ASES)
+      && mips_opts.fp32
+      && (warned_fp32 & ase->flags) != ase->flags)
+    {
+      warned_fp32 |= ase->flags;
+      as_warn (_("The `%s' extension requires 64-bit FPRs"), ase->name);
+    }
+}
+
+/* Check all enabled ASEs to see whether they are supported by the
+   chosen architecture.  */
+
+static void
+mips_check_isa_supports_ases (void)
+{
+  unsigned int i, mask;
+
+  for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+    {
+      mask = mips_ase_mask (mips_ases[i].flags);
+      if ((mips_opts.ase & mask) == mips_ases[i].flags)
+       mips_check_isa_supports_ase (&mips_ases[i]);
+    }
+}
+
+/* Set the state of ASE to ENABLED_P.  Return the mask of ASE_* flags
+   that were affected.  */
+
+static unsigned int
+mips_set_ase (const struct mips_ase *ase, bfd_boolean enabled_p)
+{
+  unsigned int mask;
+
+  mask = mips_ase_mask (ase->flags);
+  mips_opts.ase &= ~mask;
+  if (enabled_p)
+    mips_opts.ase |= ase->flags;
+  return mask;
+}
+
+/* Return the ASE called NAME, or null if none.  */
+
+static const struct mips_ase *
+mips_lookup_ase (const char *name)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+    if (strcmp (name, mips_ases[i].name) == 0)
+      return &mips_ases[i];
+  return NULL;
+}
+
+/* Return the length of a microMIPS instruction in bytes.  If bits of
+   the mask beyond the low 16 are 0, then it is a 16-bit instruction.
+   Otherwise assume a 32-bit instruction; 48-bit instructions (0x1f
+   major opcode) will require further modifications to the opcode
+   table.  */
 
 static inline unsigned int
 micromips_insn_length (const struct mips_opcode *mo)
@@ -1643,6 +2005,14 @@ micromips_insn_length (const struct mips_opcode *mo)
   return (mo->mask >> 16) == 0 ? 2 : 4;
 }
 
+/* Return the length of MIPS16 instruction OPCODE.  */
+
+static inline unsigned int
+mips16_opcode_length (unsigned long opcode)
+{
+  return (opcode >> 16) == 0 ? 2 : 4;
+}
+
 /* Return the length of instruction INSN.  */
 
 static inline unsigned int
@@ -1651,7 +2021,7 @@ insn_length (const struct mips_cl_insn *insn)
   if (mips_opts.micromips)
     return micromips_insn_length (insn->insn_mo);
   else if (mips_opts.mips16)
-    return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
+    return mips16_opcode_length (insn->insn_opcode);
   else
     return 4;
 }
@@ -1664,8 +2034,6 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
   size_t i;
 
   insn->insn_mo = mo;
-  insn->use_extend = FALSE;
-  insn->extend = 0;
   insn->insn_opcode = mo->match;
   insn->frag = NULL;
   insn->where = 0;
@@ -1675,6 +2043,7 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
   insn->noreorder_p = (mips_opts.noreorder > 0);
   insn->mips16_absolute_jump_p = 0;
   insn->complete_p = 0;
+  insn->cleared_p = 0;
 }
 
 /* Record the current MIPS16/microMIPS mode in now_seg.  */
@@ -1691,42 +2060,72 @@ mips_record_compressed_mode (void)
     si->tc_segment_info_data.micromips = mips_opts.micromips;
 }
 
+/* Read a standard MIPS instruction from BUF.  */
+
+static unsigned long
+read_insn (char *buf)
+{
+  if (target_big_endian)
+    return bfd_getb32 ((bfd_byte *) buf);
+  else
+    return bfd_getl32 ((bfd_byte *) buf);
+}
+
+/* Write standard MIPS instruction INSN to BUF.  Return a pointer to
+   the next byte.  */
+
+static char *
+write_insn (char *buf, unsigned int insn)
+{
+  md_number_to_chars (buf, insn, 4);
+  return buf + 4;
+}
+
+/* Read a microMIPS or MIPS16 opcode from BUF, given that it
+   has length LENGTH.  */
+
+static unsigned long
+read_compressed_insn (char *buf, unsigned int length)
+{
+  unsigned long insn;
+  unsigned int i;
+
+  insn = 0;
+  for (i = 0; i < length; i += 2)
+    {
+      insn <<= 16;
+      if (target_big_endian)
+       insn |= bfd_getb16 ((char *) buf);
+      else
+       insn |= bfd_getl16 ((char *) buf);
+      buf += 2;
+    }
+  return insn;
+}
+
+/* Write microMIPS or MIPS16 instruction INSN to BUF, given that the
+   instruction is LENGTH bytes long.  Return a pointer to the next byte.  */
+
+static char *
+write_compressed_insn (char *buf, unsigned int insn, unsigned int length)
+{
+  unsigned int i;
+
+  for (i = 0; i < length; i += 2)
+    md_number_to_chars (buf + i, insn >> ((length - i - 2) * 8), 2);
+  return buf + length;
+}
+
 /* Install INSN at the location specified by its "frag" and "where" fields.  */
 
 static void
 install_insn (const struct mips_cl_insn *insn)
 {
   char *f = insn->frag->fr_literal + insn->where;
-  if (!HAVE_CODE_COMPRESSION)
-    md_number_to_chars (f, insn->insn_opcode, 4);
-  else if (mips_opts.micromips)
-    {
-      unsigned int length = insn_length (insn);
-      if (length == 2)
-       md_number_to_chars (f, insn->insn_opcode, 2);
-      else if (length == 4)
-       {
-         md_number_to_chars (f, insn->insn_opcode >> 16, 2);
-         f += 2;
-         md_number_to_chars (f, insn->insn_opcode & 0xffff, 2);
-       }
-      else
-       as_bad (_("48-bit microMIPS instructions are not supported"));
-    }
-  else if (insn->mips16_absolute_jump_p)
-    {
-      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
-      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
-    }
+  if (HAVE_CODE_COMPRESSION)
+    write_compressed_insn (f, insn->insn_opcode, insn_length (insn));
   else
-    {
-      if (insn->use_extend)
-       {
-         md_number_to_chars (f, 0xf000 | insn->extend, 2);
-         f += 2;
-       }
-      md_number_to_chars (f, insn->insn_opcode, 2);
-    }
+    write_insn (f, insn->insn_opcode);
   mips_record_compressed_mode ();
 }
 
@@ -2189,39 +2588,36 @@ reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
   return ok && reglist != 0;
 }
 
-/* Return TRUE if opcode MO is valid on the currently selected ISA and
-   architecture.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
+static unsigned int
+mips_lookup_reg_pair (unsigned int regno1, unsigned int regno2,
+                     const unsigned int *map1, const unsigned int *map2,
+                     unsigned int count)
+{
+  unsigned int i;
+
+  for (i = 0; i < count; i++)
+    if (map1[i] == regno1 && map2[i] == regno2)
+      return i;
+  return ILLEGAL_REG;
+}
+
+/* Return TRUE if opcode MO is valid on the currently selected ISA, ASE
+   and architecture.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
 
 static bfd_boolean
 is_opcode_valid (const struct mips_opcode *mo)
 {
   int isa = mips_opts.isa;
+  int ase = mips_opts.ase;
   int fp_s, fp_d;
+  unsigned int i;
 
-  if (mips_opts.ase_mdmx)
-    isa |= INSN_MDMX;
-  if (mips_opts.ase_dsp)
-    isa |= INSN_DSP;
-  if (mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
-    isa |= INSN_DSP64;
-  if (mips_opts.ase_dspr2)
-    isa |= INSN_DSPR2;
-  if (mips_opts.ase_mt)
-    isa |= INSN_MT;
-  if (mips_opts.ase_mips3d)
-    isa |= INSN_MIPS3D;
-  if (mips_opts.ase_smartmips)
-    isa |= INSN_SMARTMIPS;
-  if (mips_opts.ase_mcu)
-    isa |= INSN_MCU;
-
-  /* Don't accept instructions based on the ISA if the CPU does not implement
-     all the coprocessor insns. */
-  if (NO_ISA_COP (mips_opts.arch)
-      && COP_INSN (mo->pinfo))
-    isa = 0;
-
-  if (!OPCODE_IS_MEMBER (mo, isa, mips_opts.arch))
+  if (ISA_HAS_64BIT_REGS (mips_opts.isa))
+    for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+      if ((ase & mips_ases[i].flags) == mips_ases[i].flags)
+       ase |= mips_ases[i].flags64;
+
+  if (!opcode_is_member (mo, isa, ase, mips_opts.arch))
     return FALSE;
 
   /* Check whether the instruction or macro requires single-precision or
@@ -2253,7 +2649,7 @@ is_opcode_valid (const struct mips_opcode *mo)
 static bfd_boolean
 is_opcode_valid_16 (const struct mips_opcode *mo)
 {
-  return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
+  return opcode_is_member (mo, mips_opts.isa, 0, mips_opts.arch);
 }
 
 /* Return TRUE if the size of the microMIPS opcode MO matches one
@@ -2265,6 +2661,13 @@ is_size_valid (const struct mips_opcode *mo)
   if (!mips_opts.micromips)
     return TRUE;
 
+  if (mips_opts.insn32)
+    {
+      if (mo->pinfo != INSN_MACRO && micromips_insn_length (mo) != 4)
+       return FALSE;
+      if ((mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0)
+       return FALSE;
+    }
   if (!forced_insn_length)
     return TRUE;
   if (mo->pinfo == INSN_MACRO)
@@ -2273,7 +2676,18 @@ is_size_valid (const struct mips_opcode *mo)
 }
 
 /* Return TRUE if the microMIPS opcode MO is valid for the delay slot
-   of the preceding instruction.  Always TRUE in the standard MIPS mode.  */
+   of the preceding instruction.  Always TRUE in the standard MIPS mode.
+
+   We don't accept macros in 16-bit delay slots to avoid a case where
+   a macro expansion fails because it relies on a preceding 32-bit real
+   instruction to have matched and does not handle the operands correctly.
+   The only macros that may expand to 16-bit instructions are JAL that
+   cannot be placed in a delay slot anyway, and corner cases of BALIGN
+   and BGT (that likewise cannot be placed in a delay slot) that decay to
+   a NOP.  In all these cases the macros precede any corresponding real
+   instruction definitions in the opcode table, so they will match in the
+   second pass where the size of the delay slot is ignored and therefore
+   produce correct code.  */
 
 static bfd_boolean
 is_delay_slot_valid (const struct mips_opcode *mo)
@@ -2282,7 +2696,7 @@ is_delay_slot_valid (const struct mips_opcode *mo)
     return TRUE;
 
   if (mo->pinfo == INSN_MACRO)
-    return TRUE;
+    return (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0;
   if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
       && micromips_insn_length (mo) != 4)
     return FALSE;
@@ -2449,93 +2863,88 @@ md_begin (void)
 
   bfd_set_gp_size (stdoutput, g_switch_value);
 
-#ifdef OBJ_ELF
-  if (IS_ELF)
+  /* On a native system other than VxWorks, sections must be aligned
+     to 16 byte boundaries.  When configured for an embedded ELF
+     target, we don't bother.  */
+  if (strncmp (TARGET_OS, "elf", 3) != 0
+      && strncmp (TARGET_OS, "vxworks", 7) != 0)
     {
-      /* On a native system other than VxWorks, sections must be aligned
-        to 16 byte boundaries.  When configured for an embedded ELF
-        target, we don't bother.  */
-      if (strncmp (TARGET_OS, "elf", 3) != 0
-         && strncmp (TARGET_OS, "vxworks", 7) != 0)
-       {
-         (void) bfd_set_section_alignment (stdoutput, text_section, 4);
-         (void) bfd_set_section_alignment (stdoutput, data_section, 4);
-         (void) bfd_set_section_alignment (stdoutput, bss_section, 4);
-       }
+      (void) bfd_set_section_alignment (stdoutput, text_section, 4);
+      (void) bfd_set_section_alignment (stdoutput, data_section, 4);
+      (void) bfd_set_section_alignment (stdoutput, bss_section, 4);
+    }
 
-      /* Create a .reginfo section for register masks and a .mdebug
-        section for debugging information.  */
+  /* Create a .reginfo section for register masks and a .mdebug
+     section for debugging information.  */
+  {
+    segT seg;
+    subsegT subseg;
+    flagword flags;
+    segT sec;
+
+    seg = now_seg;
+    subseg = now_subseg;
+
+    /* The ABI says this section should be loaded so that the
+       running program can access it.  However, we don't load it
+       if we are configured for an embedded target */
+    flags = SEC_READONLY | SEC_DATA;
+    if (strncmp (TARGET_OS, "elf", 3) != 0)
+      flags |= SEC_ALLOC | SEC_LOAD;
+
+    if (mips_abi != N64_ABI)
       {
-       segT seg;
-       subsegT subseg;
-       flagword flags;
-       segT sec;
-
-       seg = now_seg;
-       subseg = now_subseg;
-
-       /* The ABI says this section should be loaded so that the
-          running program can access it.  However, we don't load it
-          if we are configured for an embedded target */
-       flags = SEC_READONLY | SEC_DATA;
-       if (strncmp (TARGET_OS, "elf", 3) != 0)
-         flags |= SEC_ALLOC | SEC_LOAD;
-
-       if (mips_abi != N64_ABI)
-         {
-           sec = subseg_new (".reginfo", (subsegT) 0);
-
-           bfd_set_section_flags (stdoutput, sec, flags);
-           bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
+       sec = subseg_new (".reginfo", (subsegT) 0);
 
-           mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
-         }
-       else
-         {
-           /* The 64-bit ABI uses a .MIPS.options section rather than
-               .reginfo section.  */
-           sec = subseg_new (".MIPS.options", (subsegT) 0);
-           bfd_set_section_flags (stdoutput, sec, flags);
-           bfd_set_section_alignment (stdoutput, sec, 3);
+       bfd_set_section_flags (stdoutput, sec, flags);
+       bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
 
-           /* Set up the option header.  */
-           {
-             Elf_Internal_Options opthdr;
-             char *f;
-
-             opthdr.kind = ODK_REGINFO;
-             opthdr.size = (sizeof (Elf_External_Options)
-                            + sizeof (Elf64_External_RegInfo));
-             opthdr.section = 0;
-             opthdr.info = 0;
-             f = frag_more (sizeof (Elf_External_Options));
-             bfd_mips_elf_swap_options_out (stdoutput, &opthdr,
-                                            (Elf_External_Options *) f);
-
-             mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
-           }
-         }
+       mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
+      }
+    else
+      {
+       /* The 64-bit ABI uses a .MIPS.options section rather than
+          .reginfo section.  */
+       sec = subseg_new (".MIPS.options", (subsegT) 0);
+       bfd_set_section_flags (stdoutput, sec, flags);
+       bfd_set_section_alignment (stdoutput, sec, 3);
 
-       if (ECOFF_DEBUGGING)
-         {
-           sec = subseg_new (".mdebug", (subsegT) 0);
-           (void) bfd_set_section_flags (stdoutput, sec,
-                                         SEC_HAS_CONTENTS | SEC_READONLY);
-           (void) bfd_set_section_alignment (stdoutput, sec, 2);
-         }
-       else if (mips_flag_pdr)
-         {
-           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);
-         }
+       /* Set up the option header.  */
+       {
+         Elf_Internal_Options opthdr;
+         char *f;
+
+         opthdr.kind = ODK_REGINFO;
+         opthdr.size = (sizeof (Elf_External_Options)
+                        + sizeof (Elf64_External_RegInfo));
+         opthdr.section = 0;
+         opthdr.info = 0;
+         f = frag_more (sizeof (Elf_External_Options));
+         bfd_mips_elf_swap_options_out (stdoutput, &opthdr,
+                                        (Elf_External_Options *) f);
+
+         mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
+       }
+      }
 
-       subseg_set (seg, subseg);
+    if (ECOFF_DEBUGGING)
+      {
+       sec = subseg_new (".mdebug", (subsegT) 0);
+       (void) bfd_set_section_flags (stdoutput, sec,
+                                     SEC_HAS_CONTENTS | SEC_READONLY);
+       (void) bfd_set_section_alignment (stdoutput, sec, 2);
       }
-    }
-#endif /* OBJ_ELF */
+    else if (mips_flag_pdr)
+      {
+       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);
+      }
+
+    subseg_set (seg, subseg);
+  }
 
   if (! ECOFF_DEBUGGING)
     md_obj_begin ();
@@ -2562,13 +2971,13 @@ md_assemble (char *str)
   imm_expr.X_op = O_absent;
   imm2_expr.X_op = O_absent;
   offset_expr.X_op = O_absent;
-  imm_reloc[0] = BFD_RELOC_UNUSED;
-  imm_reloc[1] = BFD_RELOC_UNUSED;
-  imm_reloc[2] = BFD_RELOC_UNUSED;
   offset_reloc[0] = BFD_RELOC_UNUSED;
   offset_reloc[1] = BFD_RELOC_UNUSED;
   offset_reloc[2] = BFD_RELOC_UNUSED;
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   if (mips_opts.mips16)
     mips16_ip (str, &insn);
   else
@@ -2579,29 +2988,25 @@ md_assemble (char *str)
     }
 
   if (insn_error)
-    {
-      as_bad ("%s `%s'", insn_error, str);
-      return;
-    }
-
-  if (insn.insn_mo->pinfo == INSN_MACRO)
+    as_bad ("%s `%s'", insn_error, str);
+  else if (insn.insn_mo->pinfo == INSN_MACRO)
     {
       macro_start ();
       if (mips_opts.mips16)
        mips16_macro (&insn);
       else
-       macro (&insn);
+       macro (&insn, str);
       macro_end ();
     }
   else
     {
-      if (imm_expr.X_op != O_absent)
-       append_insn (&insn, &imm_expr, imm_reloc, FALSE);
-      else if (offset_expr.X_op != O_absent)
+      if (offset_expr.X_op != O_absent)
        append_insn (&insn, &offset_expr, offset_reloc, FALSE);
       else
        append_insn (&insn, NULL, unused_reloc, FALSE);
     }
+
+  mips_assembling_insn = FALSE;
 }
 
 /* Convenience functions for abstracting away the differences between
@@ -2694,6 +3099,35 @@ jalr_reloc_p (bfd_reloc_code_real_type reloc)
   return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
 }
 
+static inline bfd_boolean
+gprel16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return (reloc == BFD_RELOC_GPREL16 || reloc == BFD_RELOC_MIPS16_GPREL
+         || reloc == BFD_RELOC_MICROMIPS_GPREL16);
+}
+
+/* Return true if RELOC is a PC-relative relocation that does not have
+   full address range.  */
+
+static inline bfd_boolean
+limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  switch (reloc)
+    {
+    case BFD_RELOC_16_PCREL_S2:
+    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+      return TRUE;
+
+    case BFD_RELOC_32_PCREL:
+      return HAVE_64BIT_ADDRESSES;
+
+    default:
+      return FALSE;
+    }
+}
+
 /* Return true if the given relocation might need a matching %lo().
    This is only "might" because SVR4 R_MIPS_GOT16 relocations only
    need a matching %lo() when applied to local symbols.  */
@@ -2757,27 +3191,36 @@ reg_needs_delay (unsigned int reg)
   return 0;
 }
 
-/* Move all labels in insn_labels to the current insertion point.  */
+/* Move all labels in LABELS to the current insertion point.  TEXT_P
+   says whether the labels refer to text or data.  */
 
 static void
-mips_move_labels (void)
+mips_move_labels (struct insn_label_list *labels, bfd_boolean text_p)
 {
-  segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
   valueT val;
 
-  for (l = si->label_list; l != NULL; l = l->next)
+  for (l = labels; l != NULL; l = l->next)
     {
       gas_assert (S_GET_SEGMENT (l->label) == now_seg);
       symbol_set_frag (l->label, frag_now);
       val = (valueT) frag_now_fix ();
       /* MIPS16/microMIPS text labels are stored as odd.  */
-      if (HAVE_CODE_COMPRESSION)
+      if (text_p && HAVE_CODE_COMPRESSION)
        ++val;
       S_SET_VALUE (l->label, val);
     }
 }
 
+/* Move all labels in insn_labels to the current insertion point
+   and treat them as text labels.  */
+
+static void
+mips_move_text_labels (void)
+{
+  mips_move_labels (seg_info (now_seg)->label_list, TRUE);
+}
+
 static bfd_boolean
 s_is_linkonce (symbolS *sym, segT from_seg)
 {
@@ -2788,19 +3231,17 @@ s_is_linkonce (symbolS *sym, segT from_seg)
     {
       if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
        linkonce = TRUE;
-#ifdef OBJ_ELF
       /* 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 (symseg), ".gnu.linkonce",
                   sizeof ".gnu.linkonce" - 1) == 0)
        linkonce = TRUE;
-#endif
     }
   return linkonce;
 }
 
-/* Mark instruction labels in MIPS16/microMIPS mode.  This permits the
+/* Mark MIPS16 or microMIPS instruction label LABEL.  This permits the
    linker to handle them specially, such as generating jalx instructions
    when needed.  We also make them odd for the duration of the assembly,
    in order to generate the right sort of code.  We will make them even
@@ -2809,36 +3250,34 @@ s_is_linkonce (symbolS *sym, segT from_seg)
    to make them odd again.  */
 
 static void
-mips_compressed_mark_labels (void)
+mips_compressed_mark_label (symbolS *label)
 {
-  segment_info_type *si = seg_info (now_seg);
-  struct insn_label_list *l;
-
   gas_assert (HAVE_CODE_COMPRESSION);
 
-  for (l = si->label_list; l != NULL; l = l->next)
-   {
-      symbolS *label = l->label;
+  if (mips_opts.mips16)
+    S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
+  else
+    S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label)));
+  if ((S_GET_VALUE (label) & 1) == 0
+      /* Don't adjust the address if the label is global or weak, or
+        in a link-once section, since we'll be emitting symbol reloc
+        references to it which will be patched up by the linker, and
+        the final value of the symbol may or may not be MIPS16/microMIPS.  */
+      && !S_IS_WEAK (label)
+      && !S_IS_EXTERNAL (label)
+      && !s_is_linkonce (label, now_seg))
+    S_SET_VALUE (label, S_GET_VALUE (label) | 1);
+}
 
-#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
-      if (IS_ELF)
-       {
-         if (mips_opts.mips16)
-           S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
-         else
-           S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label)));
-       }
-#endif
-      if ((S_GET_VALUE (label) & 1) == 0
-       /* Don't adjust the address if the label is global or weak, or
-          in a link-once section, since we'll be emitting symbol reloc
-          references to it which will be patched up by the linker, and
-          the final value of the symbol may or may not be MIPS16/microMIPS.  */
-         && ! S_IS_WEAK (label)
-         && ! S_IS_EXTERNAL (label)
-         && ! s_is_linkonce (label, now_seg))
-       S_SET_VALUE (label, S_GET_VALUE (label) | 1);
-    }
+/* Mark preceding MIPS16 or microMIPS instruction labels.  */
+
+static void
+mips_compressed_mark_labels (void)
+{
+  struct insn_label_list *l;
+
+  for (l = seg_info (now_seg)->label_list; l != NULL; l = l->next)
+    mips_compressed_mark_label (l->label);
 }
 
 /* End the current frag.  Make it a variant frag and record the
@@ -3076,10 +3515,10 @@ gpr_write_mask (const struct mips_cl_insn *ip)
     {
       if (pinfo2 & INSN2_WRITE_GPR_MB)
        mask |= 1 << micromips_to_32_reg_b_map[EXTRACT_OPERAND (1, MB, *ip)];
-      if (pinfo2 & INSN2_WRITE_GPR_MHI)
+      if (pinfo2 & INSN2_WRITE_GPR_MH)
        {
-         mask |= 1 << micromips_to_32_reg_h_map[EXTRACT_OPERAND (1, MH, *ip)];
-         mask |= 1 << micromips_to_32_reg_i_map[EXTRACT_OPERAND (1, MI, *ip)];
+         mask |= 1 << micromips_to_32_reg_h_map1[EXTRACT_OPERAND (1, MH, *ip)];
+         mask |= 1 << micromips_to_32_reg_h_map2[EXTRACT_OPERAND (1, MH, *ip)];
        }
       if (pinfo2 & INSN2_WRITE_GPR_MJ)
        mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
@@ -3683,10 +4122,13 @@ fix_loongson2f (struct mips_cl_insn * ip)
 
 /* IP is a branch that has a delay slot, and we need to fill it
    automatically.   Return true if we can do that by swapping IP
-   with the previous instruction.  */
+   with the previous instruction.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
 
 static bfd_boolean
-can_swap_branch_p (struct mips_cl_insn *ip)
+can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
+  bfd_reloc_code_real_type *reloc_type)
 {
   unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
   unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
@@ -3805,13 +4247,64 @@ can_swap_branch_p (struct mips_cl_insn *ip)
       && insn_length (history) != 4)
     return FALSE;
 
+  /* On R5900 short loops need to be fixed by inserting a nop in
+     the branch delay slots.
+     A short loop can be terminated too early.  */
+  if (mips_opts.arch == CPU_R5900
+      /* Check if instruction has a parameter, ignore "j $31". */
+      && (address_expr != NULL)
+      /* Parameter must be 16 bit. */
+      && (*reloc_type == BFD_RELOC_16_PCREL_S2)
+      /* Branch to same segment. */
+      && (S_GET_SEGMENT(address_expr->X_add_symbol) == now_seg)
+      /* Branch to same code fragment. */
+      && (symbol_get_frag(address_expr->X_add_symbol) == frag_now)
+      /* Can only calculate branch offset if value is known. */
+      && symbol_constant_p(address_expr->X_add_symbol)
+      /* Check if branch is really conditional. */
+      && !((ip->insn_opcode & 0xffff0000) == 0x10000000   /* beq $0,$0 */
+       || (ip->insn_opcode & 0xffff0000) == 0x04010000   /* bgez $0 */
+       || (ip->insn_opcode & 0xffff0000) == 0x04110000)) /* bgezal $0 */
+    {
+      int distance;
+      /* Check if loop is shorter than 6 instructions including
+         branch and delay slot.  */
+      distance = frag_now_fix() - S_GET_VALUE(address_expr->X_add_symbol);
+      if (distance <= 20)
+        {
+          int i;
+          int rv;
+
+          rv = FALSE;
+          /* When the loop includes branches or jumps,
+             it is not a short loop. */
+          for (i = 0; i < (distance / 4); i++)
+            {
+              if ((history[i].cleared_p)
+                  || delayed_branch_p(&history[i]))
+                {
+                  rv = TRUE;
+                  break;
+                }
+            }
+          if (rv == FALSE)
+            {
+              /* Insert nop after branch to fix short loop. */
+              return FALSE;
+            }
+        }
+    }
+
   return TRUE;
 }
 
-/* Decide how we should add IP to the instruction stream.  */
+/* Decide how we should add IP to the instruction stream.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
 
 static enum append_method
-get_append_method (struct mips_cl_insn *ip)
+get_append_method (struct mips_cl_insn *ip, expressionS *address_expr,
+  bfd_reloc_code_real_type *reloc_type)
 {
   unsigned long pinfo;
 
@@ -3827,7 +4320,8 @@ get_append_method (struct mips_cl_insn *ip)
   /* Otherwise, it's our responsibility to fill branch delay slots.  */
   if (delayed_branch_p (ip))
     {
-      if (!branch_likely_p (ip) && can_swap_branch_p (ip))
+      if (!branch_likely_p (ip)
+         && can_swap_branch_p (ip, address_expr, reloc_type))
        return APPEND_SWAP;
 
       pinfo = ip->insn_mo->pinfo;
@@ -3919,12 +4413,7 @@ micromips_add_label (void)
 
   s = colon (micromips_label_name ());
   micromips_label_inc ();
-#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
-  if (IS_ELF)
-    S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
-#else
-  (void) s;
-#endif
+  S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
 }
 
 /* If assembling microMIPS code, then return the microMIPS reloc
@@ -3981,6 +4470,52 @@ micromips_map_reloc (bfd_reloc_code_real_type reloc)
   return reloc;
 }
 
+/* Try to resolve relocation RELOC against constant OPERAND at assembly time.
+   Return true on success, storing the resolved value in RESULT.  */
+
+static bfd_boolean
+calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
+                offsetT *result)
+{
+  switch (reloc)
+    {
+    case BFD_RELOC_MIPS_HIGHEST:
+    case BFD_RELOC_MICROMIPS_HIGHEST:
+      *result = ((operand + 0x800080008000ull) >> 48) & 0xffff;
+      return TRUE;
+
+    case BFD_RELOC_MIPS_HIGHER:
+    case BFD_RELOC_MICROMIPS_HIGHER:
+      *result = ((operand + 0x80008000ull) >> 32) & 0xffff;
+      return TRUE;
+
+    case BFD_RELOC_HI16_S:
+    case BFD_RELOC_MICROMIPS_HI16_S:
+    case BFD_RELOC_MIPS16_HI16_S:
+      *result = ((operand + 0x8000) >> 16) & 0xffff;
+      return TRUE;
+
+    case BFD_RELOC_HI16:
+    case BFD_RELOC_MICROMIPS_HI16:
+    case BFD_RELOC_MIPS16_HI16:
+      *result = (operand >> 16) & 0xffff;
+      return TRUE;
+
+    case BFD_RELOC_LO16:
+    case BFD_RELOC_MICROMIPS_LO16:
+    case BFD_RELOC_MIPS16_LO16:
+      *result = operand & 0xffff;
+      return TRUE;
+
+    case BFD_RELOC_UNUSED:
+      *result = operand;
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
 /* Output an instruction.  IP is the instruction information.
    ADDRESS_EXPR is an operand of the instruction to be used with
    RELOC_TYPE.  EXPANSIONP is true if the instruction is part of
@@ -3999,8 +4534,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
-  mips_mark_labels ();
-
   file_ase_mips16 |= mips_opts.mips16;
   file_ase_micromips |= mips_opts.micromips;
 
@@ -4018,43 +4551,13 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
 
   if (address_expr == NULL)
     ip->complete_p = 1;
-  else if (*reloc_type <= BFD_RELOC_UNUSED
+  else if (reloc_type[0] <= BFD_RELOC_UNUSED
+          && reloc_type[1] == BFD_RELOC_UNUSED
+          && reloc_type[2] == BFD_RELOC_UNUSED
           && address_expr->X_op == O_constant)
     {
-      unsigned int tmp;
-
-      ip->complete_p = 1;
       switch (*reloc_type)
        {
-       case BFD_RELOC_32:
-         ip->insn_opcode |= address_expr->X_add_number;
-         break;
-
-       case BFD_RELOC_MIPS_HIGHEST:
-         tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
-         ip->insn_opcode |= tmp & 0xffff;
-         break;
-
-       case BFD_RELOC_MIPS_HIGHER:
-         tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
-         ip->insn_opcode |= tmp & 0xffff;
-         break;
-
-       case BFD_RELOC_HI16_S:
-         tmp = (address_expr->X_add_number + 0x8000) >> 16;
-         ip->insn_opcode |= tmp & 0xffff;
-         break;
-
-       case BFD_RELOC_HI16:
-         ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
-         break;
-
-       case BFD_RELOC_UNUSED:
-       case BFD_RELOC_LO16:
-       case BFD_RELOC_MIPS_GOT_DISP:
-         ip->insn_opcode |= address_expr->X_add_number & 0xffff;
-         break;
-
        case BFD_RELOC_MIPS_JMP:
          {
            int shift;
@@ -4065,7 +4568,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                      (unsigned long) address_expr->X_add_number);
            ip->insn_opcode |= ((address_expr->X_add_number >> shift)
                                & 0x3ffffff);
-           ip->complete_p = 0;
+           ip->complete_p = 1;
          }
          break;
 
@@ -4077,7 +4580,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
            (((address_expr->X_add_number & 0x7c0000) << 3)
               | ((address_expr->X_add_number & 0xf800000) >> 7)
               | ((address_expr->X_add_number & 0x3fffc) >> 2));
-         ip->complete_p = 0;
+         ip->complete_p = 1;
          break;
 
        case BFD_RELOC_16_PCREL_S2:
@@ -4097,13 +4600,22 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                ip->insn_opcode |= ((address_expr->X_add_number >> shift)
                                    & 0xffff);
              }
-           ip->complete_p = 0;
          }
          break;
 
        default:
-         internalError ();
-       }       
+         {
+           offsetT value;
+
+           if (calculate_reloc (*reloc_type, address_expr->X_add_number,
+                                &value))
+             {
+               ip->insn_opcode |= value & 0xffff;
+               ip->complete_p = 1;
+             }
+         }
+         break;
+       }
     }
 
   if (mips_relax.sequence != 2 && !mips_opts.noreorder)
@@ -4145,7 +4657,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              frag_grow (40);
            }
 
-         mips_move_labels ();
+         mips_move_text_labels ();
 
 #ifndef NO_ECOFF_DEBUGGING
          if (ECOFF_DEBUGGING)
@@ -4185,27 +4697,22 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
        }
     }
 
-  method = get_append_method (ip);
+  method = get_append_method (ip, address_expr, reloc_type);
   branch_disp = method == APPEND_SWAP ? insn_length (history) : 0;
 
-#ifdef OBJ_ELF
-  /* The value passed to dwarf2_emit_insn is the distance between
-     the beginning of the current instruction and the address that
-     should be recorded in the debug tables.  This is normally the
-     current address.
-
-     For MIPS16/microMIPS debug info we want to use ISA-encoded
-     addresses, so we use -1 for an address higher by one than the
-     current one.
-
-     If the instruction produced is a branch that we will swap with
-     the preceding instruction, then we add the displacement by which
-     the branch will be moved backwards.  This is more appropriate
-     and for MIPS16/microMIPS code also prevents a debugger from
-     placing a breakpoint in the middle of the branch (and corrupting
-     code if software breakpoints are used).  */
-  dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0) + branch_disp);
-#endif
+  dwarf2_emit_insn (0);
+  /* We want MIPS16 and microMIPS debug info to use ISA-encoded addresses,
+     so "move" the instruction address accordingly.
+
+     Also, it doesn't seem appropriate for the assembler to reorder .loc
+     entries.  If this instruction is a branch that we are going to swap
+     with the previous instruction, the two instructions should be
+     treated as a unit, and the debug information for both instructions
+     should refer to the start of the branch sequence.  Using the
+     current position is certainly wrong when swapping a 32-bit branch
+     and a 16-bit delay slot, since the current position would then be
+     in the middle of a branch.  */
+  dwarf2_move_insn ((HAVE_CODE_COMPRESSION ? 1 : 0) - branch_disp);
 
   relax32 = (mips_relax_branch
             /* Don't try branch relaxation within .set nomacro, or within
@@ -4213,9 +4720,9 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                out that the branch was out-of-range, we'll get an error.  */
             && !mips_opts.warn_about_macros
             && (mips_opts.at || mips_pic == NO_PIC)
-            /* Don't relax BPOSGE32/64 as they have no complementing
-               branches.  */
-            && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP)));
+            /* Don't relax BPOSGE32/64 or BC1ANY2T/F and BC1ANY4T/F
+               as they have no complementing branches.  */
+            && !(ip->insn_mo->ase & (ASE_MIPS3D | ASE_DSP64 | ASE_DSP)));
 
   if (!HAVE_CODE_COMPRESSION
       && address_expr
@@ -4279,9 +4786,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                         history[0].mips16_absolute_jump_p),
                        make_expr_symbol (address_expr), 0);
     }
-  else if (mips_opts.mips16
-          && ! ip->use_extend
-          && *reloc_type != BFD_RELOC_MIPS16_JMP)
+  else if (mips_opts.mips16 && insn_length (ip) == 2)
     {
       if (!delayed_branch_p (ip))
        /* Make sure there is enough room to swap this instruction with
@@ -4344,16 +4849,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
       /* In a compound relocation, it is the final (outermost)
         operator that determines the relocated field.  */
       howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
-
-      if (howto == NULL)
-       {
-         /* To reproduce this failure try assembling gas/testsuites/
-            gas/mips/mips16-intermix.s with a mips-ecoff targeted
-            assembler.  */
-         as_bad (_("Unsupported MIPS relocation number %d"),
-                 final_type[i - 1]);
-         howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
-       }
+      if (!howto)
+       abort ();
 
       if (i > 1)
        howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
@@ -4390,6 +4887,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              || lo16_reloc_p (reloc_type[0])))
        ip->fixp[0]->fx_no_overflow = 1;
 
+      /* These relocations can have an addend that won't fit in 2 octets.  */
+      if (reloc_type[0] == BFD_RELOC_MICROMIPS_7_PCREL_S1
+         || reloc_type[0] == BFD_RELOC_MICROMIPS_10_PCREL_S1)
+       ip->fixp[0]->fx_no_overflow = 1;
+
       if (mips_relax.sequence)
        {
          if (mips_relax.first_fixup == 0)
@@ -4473,7 +4975,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
            move_insn (ip, delay.frag, delay.where);
            move_insn (&delay, ip->frag, ip->where + insn_length (ip));
          }
-       else if (relaxed_branch)
+       else if (relaxed_branch || delay.frag != ip->frag)
          {
            /* Add the delay slot instruction to the end of the
               current frag and shrink the fixed part of the
@@ -4500,7 +5002,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   /* If we have just completed an unconditional branch, clear the history.  */
   if ((delayed_branch_p (&history[1]) && uncond_branch_p (&history[1]))
       || (compact_branch_p (&history[0]) && uncond_branch_p (&history[0])))
-    mips_no_prev_insn ();
+    {
+      unsigned int i;
+
+      mips_no_prev_insn ();
+
+      for (i = 0; i < ARRAY_SIZE (history); i++)
+       history[i].cleared_p = 1;
+    }
 
   /* We need to emit a label at the end of branch-likely macros.  */
   if (emit_branch_likely_macro)
@@ -4513,7 +5022,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   mips_clear_insn_labels ();
 }
 
-/* Forget that there was any previous instruction or label.  */
+/* Forget that there was any previous instruction or label.
+   When BRANCH is true, the branch history is also flushed.  */
 
 static void
 mips_no_prev_insn (void)
@@ -4537,7 +5047,7 @@ mips_emit_delays (void)
        {
          while (nops-- > 0)
            add_fixed_insn (NOP_INSN);
-         mips_move_labels ();
+         mips_move_text_labels ();
        }
     }
   mips_no_prev_insn ();
@@ -4581,7 +5091,7 @@ start_noreorder (void)
             decrease the size of prev_nop_frag.  */
          frag_wane (frag_now);
          frag_new (0);
-         mips_move_labels ();
+         mips_move_text_labels ();
        }
       mips_mark_labels ();
       mips_clear_insn_labels ();
@@ -4733,21 +5243,21 @@ macro_end (void)
 /* Instruction operand formats used in macros that vary between
    standard MIPS and microMIPS code.  */
 
-static const char * const brk_fmt[2] = { "c", "mF" };
+static const char * const brk_fmt[2][2] = { { "c", "c" }, { "mF", "c" } };
 static const char * const cop12_fmt[2] = { "E,o(b)", "E,~(b)" };
 static const char * const jalr_fmt[2] = { "d,s", "t,s" };
 static const char * const lui_fmt[2] = { "t,u", "s,u" };
 static const char * const mem12_fmt[2] = { "t,o(b)", "t,~(b)" };
-static const char * const mfhl_fmt[2] = { "d", "mj" };
+static const char * const mfhl_fmt[2][2] = { { "d", "d" }, { "mj", "s" } };
 static const char * const shft_fmt[2] = { "d,w,<", "t,r,<" };
 static const char * const trap_fmt[2] = { "s,t,q", "s,t,|" };
 
-#define BRK_FMT (brk_fmt[mips_opts.micromips])
+#define BRK_FMT (brk_fmt[mips_opts.micromips][mips_opts.insn32])
 #define COP12_FMT (cop12_fmt[mips_opts.micromips])
 #define JALR_FMT (jalr_fmt[mips_opts.micromips])
 #define LUI_FMT (lui_fmt[mips_opts.micromips])
 #define MEM12_FMT (mem12_fmt[mips_opts.micromips])
-#define MFHL_FMT (mfhl_fmt[mips_opts.micromips])
+#define MFHL_FMT (mfhl_fmt[mips_opts.micromips][mips_opts.insn32])
 #define SHFT_FMT (shft_fmt[mips_opts.micromips])
 #define TRAP_FMT (trap_fmt[mips_opts.micromips])
 
@@ -4765,8 +5275,15 @@ macro_read_relocs (va_list *args, bfd_reloc_code_real_type *r)
   if (next >= 0)
     r[0] = (bfd_reloc_code_real_type) next;
   else
-    for (i = 0; i < 3; i++)
-      r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+    {
+      for (i = 0; i < 3; i++)
+       r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+      /* This function is only used for 16-bit relocation fields.
+        To make the macro code simpler, treat an unrelocated value
+        in the same way as BFD_RELOC_LO16.  */
+      if (r[0] == BFD_RELOC_UNUSED)
+       r[0] = BFD_RELOC_LO16;
+    }
 }
 
 /* Build an instruction created by a macro expansion.  This is passed
@@ -4863,6 +5380,11 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
                              INSMSB, insn, va_arg (args, int));
              continue;
 
+           case 'J':
+             gas_assert (!mips_opts.micromips);
+             INSERT_OPERAND (0, CODE10, insn, va_arg (args, int));
+             continue;
+
            case 'C':
            case 'G':
            case 'H':
@@ -4879,14 +5401,17 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              INSERT_OPERAND (0, SEQI, insn, va_arg (args, int));
              continue;
 
+           case 'j':
+             INSERT_OPERAND (mips_opts.micromips, EVAOFFSET, insn, va_arg (args, int));
+             continue;
+
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
        case '2':
-         gas_assert (!mips_opts.micromips);
-         INSERT_OPERAND (0, BP, insn, va_arg (args, int));
+         INSERT_OPERAND (mips_opts.micromips, BP, insn, va_arg (args, int));
          continue;
 
        case 'n':
@@ -4898,8 +5423,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'c':
-         gas_assert (!mips_opts.micromips);
-         INSERT_OPERAND (0, CODE, insn, va_arg (args, int));
+         INSERT_OPERAND (mips_opts.micromips, CODE, insn, va_arg (args, int));
          continue;
 
        case 'W':
@@ -5035,12 +5559,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'C':
          gas_assert (!mips_opts.micromips);
-         INSERT_OPERAND (0, COPZ, insn, va_arg (args, unsigned long));
+         INSERT_OPERAND (0, COPZ, insn, va_arg (args, int));
          continue;
 
        case 'k':
          INSERT_OPERAND (mips_opts.micromips,
-                         CACHE, insn, va_arg (args, unsigned long));
+                         CACHE, insn, va_arg (args, int));
          continue;
 
        case '|':
@@ -5055,12 +5579,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case '\\':
          INSERT_OPERAND (mips_opts.micromips,
-                         3BITPOS, insn, va_arg (args, unsigned int));
+                         3BITPOS, insn, va_arg (args, int));
          continue;
 
        case '~':
          INSERT_OPERAND (mips_opts.micromips,
-                         OFFSET12, insn, va_arg (args, unsigned long));
+                         OFFSET12, insn, va_arg (args, int));
          continue;
 
        case 'N':
@@ -5085,12 +5609,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              break;
 
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
        default:
-         internalError ();
+         abort ();
        }
       break;
     }
@@ -5164,16 +5688,6 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
          MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
          continue;
 
-       case 'Y':
-         {
-           int regno;
-
-           regno = va_arg (*args, int);
-           regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
-           MIPS16_INSERT_OPERAND (REG32R, insn, regno);
-         }
-         continue;
-
        case '<':
        case '>':
        case '4':
@@ -5191,15 +5705,15 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
        case 'p':
        case 'q':
          {
+           offsetT value;
+
            gas_assert (ep != NULL);
 
            if (ep->X_op != O_constant)
              *r = (int) BFD_RELOC_UNUSED + c;
-           else
+           else if (calculate_reloc (*r, ep->X_add_number, &value))
              {
-               mips16_immed (NULL, 0, c, ep->X_add_number, FALSE, FALSE,
-                             FALSE, &insn.insn_opcode, &insn.use_extend,
-                             &insn.extend);
+               mips16_immed (NULL, 0, c, *r, value, 0, &insn.insn_opcode);
                ep = NULL;
                *r = BFD_RELOC_UNUSED;
              }
@@ -5266,8 +5780,11 @@ macro_build_jalr (expressionS *ep, int cprestore)
     }
   if (mips_opts.micromips)
     {
-      jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
-      if (MIPS_JALR_HINT_P (ep))
+      jalr = ((mips_opts.noreorder && !cprestore) || mips_opts.insn32
+             ? "jalr" : "jalrs");
+      if (MIPS_JALR_HINT_P (ep)
+         || mips_opts.insn32
+         || (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
        macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
       else
        macro_build (NULL, jalr, "mj", PIC_CALL_REG);
@@ -5947,6 +6464,7 @@ move_register (int dest, int source)
   /* Prefer to use a 16-bit microMIPS instruction unless the previous
      instruction specifically requires a 32-bit one.  */
   if (mips_opts.micromips
+      && !mips_opts.insn32
       && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
     macro_build (NULL, "move", "mp,mj", dest, source);
   else
@@ -6143,7 +6661,7 @@ macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
       break;
     case M_BGEZALL:
       gas_assert (mips_opts.micromips);
-      br = "bgezals";
+      br = mips_opts.insn32 ? "bgezal" : "bgezals";
       brneg = "bltz";
       call = 1;
       break;
@@ -6170,7 +6688,7 @@ macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
       break;
     case M_BLTZALL:
       gas_assert (mips_opts.micromips);
-      br = "bltzals";
+      br = mips_opts.insn32 ? "bltzal" : "bltzals";
       brneg = "bgez";
       call = 1;
       break;
@@ -6223,6 +6741,48 @@ macro_build_branch_rsrt (int type, expressionS *ep,
     macro_build (ep, br, "s,t,p", sreg, treg);
 }
 
+/* Return the high part that should be loaded in order to make the low
+   part of VALUE accessible using an offset of OFFBITS bits.  */
+
+static offsetT
+offset_high_part (offsetT value, unsigned int offbits)
+{
+  offsetT bias;
+  addressT low_mask;
+
+  if (offbits == 0)
+    return value;
+  bias = 1 << (offbits - 1);
+  low_mask = bias * 2 - 1;
+  return (value + bias) & ~low_mask;
+}
+
+/* Return true if the value stored in offset_expr and offset_reloc
+   fits into a signed offset of OFFBITS bits.  RANGE is the maximum
+   amount that the caller wants to add without inducing overflow
+   and ALIGN is the known alignment of the value in bytes.  */
+
+static bfd_boolean
+small_offset_p (unsigned int range, unsigned int align, unsigned int offbits)
+{
+  if (offbits == 16)
+    {
+      /* Accept any relocation operator if overflow isn't a concern.  */
+      if (range < align && *offset_reloc != BFD_RELOC_UNUSED)
+       return TRUE;
+
+      /* These relocations are guaranteed not to overflow in correct links.  */
+      if (*offset_reloc == BFD_RELOC_MIPS_LITERAL
+         || gprel16_reloc_p (*offset_reloc))
+       return TRUE;
+    }
+  if (offset_expr.X_op == O_constant
+      && offset_high_part (offset_expr.X_add_number, offbits) == 0
+      && offset_high_part (offset_expr.X_add_number + range, offbits) == 0)
+    return TRUE;
+  return FALSE;
+}
+
 /*
  *                     Build macros
  *   This routine implements the seemingly endless macro or synthesized
@@ -6242,7 +6802,7 @@ macro_build_branch_rsrt (int type, expressionS *ep,
  * we're missing.
  */
 static void
-macro (struct mips_cl_insn *ip)
+macro (struct mips_cl_insn *ip, char *str)
 {
   unsigned int treg, sreg, dreg, breg;
   unsigned int tempreg;
@@ -6256,19 +6816,17 @@ macro (struct mips_cl_insn *ip)
   const char *fmt;
   int likely = 0;
   int coproc = 0;
-  int off12 = 0;
+  int offbits = 16;
   int call = 0;
   int jals = 0;
   int dbl = 0;
   int imm = 0;
   int ust = 0;
   int lp = 0;
-  int ab = 0;
-  int off0 = 0;
+  bfd_boolean large_offset;
   int off;
-  offsetT maxnum;
-  bfd_reloc_code_real_type r;
   int hold_mips_optimize;
+  unsigned int align;
 
   gas_assert (! mips_opts.mips16);
 
@@ -6286,6 +6844,7 @@ macro (struct mips_cl_insn *ip)
   expr1.X_op_symbol = NULL;
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
+  align = 1;
 
   switch (mask)
     {
@@ -6401,10 +6960,15 @@ macro (struct mips_cl_insn *ip)
        case 2:
          macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
          break;
-       default:
+       case 1:
+       case 3:
          macro_build (NULL, "balign", "t,s,2", treg, sreg,
                       (int) imm_expr.X_add_number);
          break;
+       default:
+         as_bad (_("BALIGN immediate not 0, 1, 2 or 3 (%lu)"),
+                 (unsigned long) imm_expr.X_add_number);
+         break;
        }
       break;
 
@@ -6464,17 +7028,7 @@ macro (struct mips_cl_insn *ip)
       likely = 1;
     case M_BGT_I:
       /* Check for > max integer.  */
-      maxnum = 0x7fffffff;
-      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
-       {
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-       }
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= maxnum
-         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
        {
        do_false:
          /* Result is always false.  */
@@ -6504,18 +7058,7 @@ macro (struct mips_cl_insn *ip)
                                 &offset_expr, sreg);
          break;
        }
-      maxnum = 0x7fffffff;
-      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
-       {
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-       }
-      maxnum = - maxnum - 1;
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number <= maxnum
-         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number <= GPR_SMIN)
        {
        do_true:
          /* result is always true */
@@ -6628,17 +7171,7 @@ macro (struct mips_cl_insn *ip)
     case M_BLEL_I:
       likely = 1;
     case M_BLE_I:
-      maxnum = 0x7fffffff;
-      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
-       {
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-         maxnum <<= 16;
-         maxnum |= 0xffff;
-       }
-      if (imm_expr.X_op == O_constant
-         && imm_expr.X_add_number >= maxnum
-         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number >= GPR_SMAX)
        goto do_true;
       if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
@@ -7057,12 +7590,10 @@ macro (struct mips_cl_insn *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)
+      if (small_offset_p (0, align, 16))
        {
-         macro_build (&offset_expr, ADDRESS_ADDI_INSN,
-                      "t,r,j", treg, sreg, BFD_RELOC_LO16);
+         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg,
+                      -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
          break;
        }
 
@@ -7248,7 +7779,7 @@ macro (struct mips_cl_insn *ip)
            {
              expr1.X_add_number = offset_expr.X_add_number;
              offset_expr.X_add_number =
-               ((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000;
+               SEXT_16BIT (offset_expr.X_add_number);
              load_got_offset (tempreg, &offset_expr);
              offset_expr.X_add_number = expr1.X_add_number;
              /* If we are going to add in a base register, and the
@@ -7476,8 +8007,7 @@ macro (struct mips_cl_insn *ip)
 
              used_at = 1;
            }
-         offset_expr.X_add_number =
-           ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000;
+         offset_expr.X_add_number = SEXT_16BIT (expr1.X_add_number);
          relax_switch ();
 
          if (gpdelay)
@@ -7640,26 +8170,17 @@ macro (struct mips_cl_insn *ip)
 
     case M_MSGSND:
       gas_assert (!mips_opts.micromips);
-      {
-       unsigned long temp = (treg << 16) | (0x01);
-       macro_build (NULL, "c2", "C", temp);
-      }
+      macro_build (NULL, "c2", "C", (treg << 16) | 0x01);
       break;
 
     case M_MSGLD:
       gas_assert (!mips_opts.micromips);
-      {
-       unsigned long temp = (0x02);
-       macro_build (NULL, "c2", "C", temp);
-      }
+      macro_build (NULL, "c2", "C", 0x02);
       break;
 
     case M_MSGLD_T:
       gas_assert (!mips_opts.micromips);
-      {
-       unsigned long temp = (treg << 16) | (0x02);
-       macro_build (NULL, "c2", "C", temp);
-      }
+      macro_build (NULL, "c2", "C", (treg << 16) | 0x02);
       break;
 
     case M_MSGWAIT:
@@ -7669,10 +8190,7 @@ macro (struct mips_cl_insn *ip)
 
     case M_MSGWAIT_T:
       gas_assert (!mips_opts.micromips);
-      {
-       unsigned long temp = (treg << 16) | 0x03;
-       macro_build (NULL, "c2", "C", temp);
-      }
+      macro_build (NULL, "c2", "C", (treg << 16) | 0x03);
       break;
 
     case M_J_A:
@@ -7693,6 +8211,11 @@ macro (struct mips_cl_insn *ip)
       /* Fall through.  */
     case M_JALS_2:
       gas_assert (mips_opts.micromips);
+      if (mips_opts.insn32)
+       {
+         as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+         break;
+       }
       jals = 1;
       goto jal;
     case M_JAL_1:
@@ -7703,7 +8226,10 @@ macro (struct mips_cl_insn *ip)
       if (mips_pic == NO_PIC)
        {
          s = jals ? "jalrs" : "jalr";
-         if (mips_opts.micromips && dreg == RA)
+         if (mips_opts.micromips
+             && !mips_opts.insn32
+             && dreg == RA
+             && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
            macro_build (NULL, s, "mj", sreg);
          else
            macro_build (NULL, s, JALR_FMT, dreg, sreg);
@@ -7716,9 +8242,14 @@ macro (struct mips_cl_insn *ip)
          if (sreg != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
 
-         s = (mips_opts.micromips && (!mips_opts.noreorder || cprestore)
+         s = ((mips_opts.micromips
+               && !mips_opts.insn32
+               && (!mips_opts.noreorder || cprestore))
               ? "jalrs" : "jalr");
-         if (mips_opts.micromips && dreg == RA)
+         if (mips_opts.micromips
+             && !mips_opts.insn32
+             && dreg == RA
+             && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
            macro_build (NULL, s, "mj", sreg);
          else
            macro_build (NULL, s, JALR_FMT, dreg, sreg);
@@ -7755,6 +8286,11 @@ macro (struct mips_cl_insn *ip)
 
     case M_JALS_A:
       gas_assert (mips_opts.micromips);
+      if (mips_opts.insn32)
+       {
+         as_bad (_("Opcode not supported in the `insn32' mode `%s'"), str);
+         break;
+       }
       jals = 1;
       /* Fall through.  */
     case M_JAL_A:
@@ -7896,49 +8432,109 @@ macro (struct mips_cl_insn *ip)
 
       break;
 
+    case M_LBUE_AB:
+      s = "lbue";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LHUE_AB:
+      s = "lhue";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LBE_AB:
+      s = "lbe";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LHE_AB:
+      s = "lhe";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LLE_AB:
+      s = "lle";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LWE_AB:
+      s = "lwe";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LWLE_AB:
+      s = "lwle";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_LWRE_AB:
+      s = "lwre";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SBE_AB:
+      s = "sbe";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SCE_AB:
+      s = "sce";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SHE_AB:
+      s = "she";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SWE_AB:
+      s = "swe";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SWLE_AB:
+      s = "swle";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
+    case M_SWRE_AB:
+      s = "swre";
+      fmt = "t,+j(b)";
+      offbits = 9;
+      goto ld_st;
     case M_ACLR_AB:
-      ab = 1;
-    case M_ACLR_OB:
       s = "aclr";
       treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
       fmt = "\\,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_ASET_AB:
-      ab = 1;
-    case M_ASET_OB:
       s = "aset";
       treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
       fmt = "\\,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_LB_AB:
-      ab = 1;
       s = "lb";
       fmt = "t,o(b)";
       goto ld;
     case M_LBU_AB:
-      ab = 1;
       s = "lbu";
       fmt = "t,o(b)";
       goto ld;
     case M_LH_AB:
-      ab = 1;
       s = "lh";
       fmt = "t,o(b)";
       goto ld;
     case M_LHU_AB:
-      ab = 1;
       s = "lhu";
       fmt = "t,o(b)";
       goto ld;
     case M_LW_AB:
-      ab = 1;
       s = "lw";
       fmt = "t,o(b)";
       goto ld;
     case M_LWC0_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "lwc0";
       fmt = "E,o(b)";
@@ -7946,23 +8542,19 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_LWC1_AB:
-      ab = 1;
       s = "lwc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LWC2_AB:
-      ab = 1;
-    case M_LWC2_OB:
       s = "lwc2";
       fmt = COP12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "lwc3";
       fmt = "E,o(b)";
@@ -7970,136 +8562,113 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_LWL_AB:
-      ab = 1;
-    case M_LWL_OB:
       s = "lwl";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LWR_AB:
-      ab = 1;
-    case M_LWR_OB:
       s = "lwr";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LDC1_AB:
-      ab = 1;
       s = "ldc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDC2_AB:
-      ab = 1;
-    case M_LDC2_OB:
       s = "ldc2";
       fmt = COP12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
+      /* Itbl support may require additional care here.  */
+      coproc = 1;
+      goto ld_st;
+    case M_LQC2_AB:
+      s = "lqc2";
+      fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDC3_AB:
-      ab = 1;
       s = "ldc3";
       fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDL_AB:
-      ab = 1;
-    case M_LDL_OB:
       s = "ldl";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LDR_AB:
-      ab = 1;
-    case M_LDR_OB:
       s = "ldr";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LL_AB:
-      ab = 1;
-    case M_LL_OB:
       s = "ll";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LLD_AB:
-      ab = 1;
-    case M_LLD_OB:
       s = "lld";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LWU_AB:
-      ab = 1;
-    case M_LWU_OB:
       s = "lwu";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LWP_AB:
-      ab = 1;
-    case M_LWP_OB:
       gas_assert (mips_opts.micromips);
       s = "lwp";
       fmt = "t,~(b)";
-      off12 = 1;
+      offbits = 12;
       lp = 1;
       goto ld;
     case M_LDP_AB:
-      ab = 1;
-    case M_LDP_OB:
       gas_assert (mips_opts.micromips);
       s = "ldp";
       fmt = "t,~(b)";
-      off12 = 1;
+      offbits = 12;
       lp = 1;
       goto ld;
     case M_LWM_AB:
-      ab = 1;
-    case M_LWM_OB:
       gas_assert (mips_opts.micromips);
       s = "lwm";
       fmt = "n,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_LDM_AB:
-      ab = 1;
-    case M_LDM_OB:
       gas_assert (mips_opts.micromips);
       s = "ldm";
       fmt = "n,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
 
     ld:
-      if (breg == treg + lp)
+      /* We don't want to use $0 as tempreg.  */
+      if (breg == treg + lp || treg + lp == ZERO)
        goto ld_st;
       else
        tempreg = treg + lp;
       goto ld_noat;
 
     case M_SB_AB:
-      ab = 1;
       s = "sb";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SH_AB:
-      ab = 1;
       s = "sh";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SW_AB:
-      ab = 1;
       s = "sw";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SWC0_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "swc0";
       fmt = "E,o(b)";
@@ -8107,23 +8676,19 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_SWC1_AB:
-      ab = 1;
       s = "swc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_SWC2_AB:
-      ab = 1;
-    case M_SWC2_OB:
       s = "swc2";
       fmt = COP12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_SWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "swc3";
       fmt = "E,o(b)";
@@ -8131,65 +8696,65 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_SWL_AB:
-      ab = 1;
-    case M_SWL_OB:
       s = "swl";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SWR_AB:
-      ab = 1;
-    case M_SWR_OB:
       s = "swr";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SC_AB:
-      ab = 1;
-    case M_SC_OB:
       s = "sc";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SCD_AB:
-      ab = 1;
-    case M_SCD_OB:
       s = "scd";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_CACHE_AB:
-      ab = 1;
-    case M_CACHE_OB:
       s = "cache";
       fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
+      goto ld_st;
+    case M_CACHEE_AB:
+      s = "cachee";
+      fmt = "k,+j(b)";
+      offbits = 9;
       goto ld_st;
     case M_PREF_AB:
-      ab = 1;
-    case M_PREF_OB:
       s = "pref";
       fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
+      goto ld_st;
+    case M_PREFE_AB:
+      s = "prefe";
+      fmt = "k,+j(b)";
+      offbits = 9;
       goto ld_st;
     case M_SDC1_AB:
-      ab = 1;
       s = "sdc1";
       fmt = "T,o(b)";
       coproc = 1;
       /* Itbl support may require additional care here.  */
       goto ld_st;
     case M_SDC2_AB:
-      ab = 1;
-    case M_SDC2_OB:
       s = "sdc2";
       fmt = COP12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
+      /* Itbl support may require additional care here.  */
+      coproc = 1;
+      goto ld_st;
+    case M_SQC2_AB:
+      s = "sqc2";
+      fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_SDC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "sdc3";
       fmt = "E,o(b)";
@@ -8197,64 +8762,76 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_SDL_AB:
-      ab = 1;
-    case M_SDL_OB:
       s = "sdl";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SDR_AB:
-      ab = 1;
-    case M_SDR_OB:
       s = "sdr";
       fmt = MEM12_FMT;
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SWP_AB:
-      ab = 1;
-    case M_SWP_OB:
       gas_assert (mips_opts.micromips);
       s = "swp";
       fmt = "t,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_SDP_AB:
-      ab = 1;
-    case M_SDP_OB:
       gas_assert (mips_opts.micromips);
       s = "sdp";
       fmt = "t,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_SWM_AB:
-      ab = 1;
-    case M_SWM_OB:
       gas_assert (mips_opts.micromips);
       s = "swm";
       fmt = "n,~(b)";
-      off12 = 1;
+      offbits = 12;
       goto ld_st;
     case M_SDM_AB:
-      ab = 1;
-    case M_SDM_OB:
       gas_assert (mips_opts.micromips);
       s = "sdm";
       fmt = "n,~(b)";
-      off12 = 1;
+      offbits = 12;
 
     ld_st:
       tempreg = AT;
-      used_at = 1;
     ld_noat:
-      if (coproc
-         && NO_ISA_COP (mips_opts.arch)
-         && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
+      if (small_offset_p (0, align, 16))
        {
-         as_bad (_("Opcode not supported on this processor: %s"),
-                 mips_cpu_info_from_arch (mips_opts.arch)->name);
+         /* The first case exists for M_LD_AB and M_SD_AB, which are
+            macros for o32 but which should act like normal instructions
+            otherwise.  */
+         if (offbits == 16)
+           macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0],
+                        offset_reloc[1], offset_reloc[2], breg);
+         else if (small_offset_p (0, align, offbits))
+           {
+             if (offbits == 0)
+               macro_build (NULL, s, fmt, treg, breg);
+             else
+               macro_build (NULL, s, fmt, treg,
+                            (int) offset_expr.X_add_number, breg);
+           }
+         else
+           {
+             if (tempreg == AT)
+               used_at = 1;
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+                          tempreg, breg, -1, offset_reloc[0],
+                          offset_reloc[1], offset_reloc[2]);
+             if (offbits == 0)
+               macro_build (NULL, s, fmt, treg, tempreg);
+             else
+               macro_build (NULL, s, fmt, treg, 0, tempreg);
+           }
          break;
        }
 
+      if (tempreg == AT)
+       used_at = 1;
+
       if (offset_expr.X_op != O_constant
          && offset_expr.X_op != O_symbol)
        {
@@ -8275,72 +8852,40 @@ macro (struct mips_cl_insn *ip)
         is in non PIC code.  */
       if (offset_expr.X_op == O_constant)
        {
-         int hipart = 0;
+         expr1.X_add_number = offset_high_part (offset_expr.X_add_number,
+                                                offbits == 0 ? 16 : offbits);
+         offset_expr.X_add_number -= expr1.X_add_number;
 
-         expr1.X_add_number = offset_expr.X_add_number;
-         normalize_address_expr (&expr1);
-         if (!off12 && !IS_SEXT_16BIT_NUM (expr1.X_add_number))
-           {
-             expr1.X_add_number = ((expr1.X_add_number + 0x8000)
-                                   & ~(bfd_vma) 0xffff);
-             hipart = 1;
-           }
-         else if (off12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number))
-           {
-             expr1.X_add_number = ((expr1.X_add_number + 0x800)
-                                   & ~(bfd_vma) 0xfff);
-             hipart = 1;
-           }
-         if (hipart)
-           {
-             load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
-             if (breg != 0)
-               macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                            tempreg, tempreg, breg);
-             breg = tempreg;
-           }
-         if (off0)
+         load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+         if (breg != 0)
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                        tempreg, tempreg, breg);
+         if (offbits == 0)
            {
-             if (offset_expr.X_add_number == 0)
-               tempreg = breg;
-             else
+             if (offset_expr.X_add_number != 0)
                macro_build (&offset_expr, ADDRESS_ADDI_INSN,
-                            "t,r,j", tempreg, breg, BFD_RELOC_LO16);
+                            "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
              macro_build (NULL, s, fmt, treg, tempreg);
            }
-         else if (!off12)
-           macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
+         else if (offbits == 16)
+           macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
          else
-           macro_build (NULL, s, fmt,
-                        treg, (unsigned long) offset_expr.X_add_number, breg);
+           macro_build (NULL, s, fmt, treg,
+                        (int) offset_expr.X_add_number, tempreg);
        }
-      else if (off12 || off0)
+      else if (offbits != 16)
        {
-         /* A 12-bit or 0-bit offset field is too narrow to be used
-            for a low-part relocation, so load the whole address into
-            the auxillary register.  In the case of "A(b)" addresses,
-            we first load absolute address "A" into the register and
-            then add base register "b".  In the case of "o(b)" addresses,
-            we simply need to add 16-bit offset "o" to base register "b", and
-            offset_reloc already contains the relocations associated
-            with "o".  */
-         if (ab)
-           {
-             load_address (tempreg, &offset_expr, &used_at);
-             if (breg != 0)
-               macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                            tempreg, tempreg, breg);
-           }
-         else
-           macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
-                        tempreg, breg, -1,
-                        offset_reloc[0], offset_reloc[1], offset_reloc[2]);
-         expr1.X_add_number = 0;
-         if (off0)
+         /* The offset field is too narrow to be used for a low-part
+            relocation, so load the whole address into the auxillary
+            register.  */
+         load_address (tempreg, &offset_expr, &used_at);
+         if (breg != 0)
+           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                        tempreg, tempreg, breg);
+         if (offbits == 0)
            macro_build (NULL, s, fmt, treg, tempreg);
          else
-           macro_build (NULL, s, fmt,
-                        treg, (unsigned long) expr1.X_add_number, tempreg);
+           macro_build (NULL, s, fmt, treg, 0, tempreg);
        }
       else if (mips_pic == NO_PIC)
        {
@@ -8642,6 +9187,24 @@ macro (struct mips_cl_insn *ip)
 
       break;
 
+    case M_JRADDIUSP:
+      gas_assert (mips_opts.micromips);
+      gas_assert (mips_opts.insn32);
+      start_noreorder ();
+      macro_build (NULL, "jr", "s", RA);
+      expr1.X_add_number = EXTRACT_OPERAND (1, IMMP, *ip) << 2;
+      macro_build (&expr1, "addiu", "t,r,j", SP, SP, BFD_RELOC_LO16);
+      end_noreorder ();
+      break;
+
+    case M_JRC:
+      gas_assert (mips_opts.micromips);
+      gas_assert (mips_opts.insn32);
+      macro_build (NULL, "jr", "s", sreg);
+      if (mips_opts.noreorder)
+       macro_build (NULL, "nop", "");
+      break;
+
     case M_LI:
     case M_LI_S:
       load_register (treg, &imm_expr, 0);
@@ -8780,16 +9343,11 @@ macro (struct mips_cl_insn *ip)
                  && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
-       {
-         if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
-           {
-             macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
-                          BFD_RELOC_MIPS_LITERAL, mips_gp_register);
-             break;
-           }
-         breg = mips_gp_register;
-         r = BFD_RELOC_MIPS_LITERAL;
-         goto dob;
+       {
+         breg = mips_gp_register;
+         offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
+         offset_reloc[1] = BFD_RELOC_UNUSED;
+         offset_reloc[2] = BFD_RELOC_UNUSED;
        }
       else
        {
@@ -8804,47 +9362,15 @@ macro (struct mips_cl_insn *ip)
              macro_build_lui (&offset_expr, AT);
            }
 
-         if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
-           {
-             macro_build (&offset_expr, "ldc1", "T,o(b)",
-                          treg, BFD_RELOC_LO16, AT);
-             break;
-           }
          breg = AT;
-         r = BFD_RELOC_LO16;
-         goto dob;
-       }
-
-    case M_L_DOB:
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-        to adjust when loading from memory.  */
-      r = BFD_RELOC_LO16;
-    dob:
-      gas_assert (!mips_opts.micromips);
-      gas_assert (mips_opts.isa == ISA_MIPS1);
-      macro_build (&offset_expr, "lwc1", "T,o(b)",
-                  target_big_endian ? treg + 1 : treg, r, breg);
-      /* FIXME: A possible overflow which I don't know how to deal
-        with.  */
-      offset_expr.X_add_number += 4;
-      macro_build (&offset_expr, "lwc1", "T,o(b)",
-                  target_big_endian ? treg : treg + 1, r, breg);
-      break;
-
-    case M_S_DOB:
-      gas_assert (!mips_opts.micromips);
-      gas_assert (mips_opts.isa == ISA_MIPS1);
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-        to adjust when storing to memory.  */
-      macro_build (&offset_expr, "swc1", "T,o(b)",
-                  target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
-      offset_expr.X_add_number += 4;
-      macro_build (&offset_expr, "swc1", "T,o(b)",
-                  target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
-      break;
+         offset_reloc[0] = BFD_RELOC_LO16;
+         offset_reloc[1] = BFD_RELOC_UNUSED;
+         offset_reloc[2] = BFD_RELOC_UNUSED;
+       }
+      align = 8;
+      /* Fall through */
 
     case M_L_DAB:
-      gas_assert (!mips_opts.micromips);
       /*
        * The MIPS assembler seems to check for X_add_number not
        * being double aligned and generating:
@@ -8859,7 +9385,7 @@ macro (struct mips_cl_insn *ip)
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
-      if (mips_opts.isa != ISA_MIPS1)
+      if (CPU_HAS_LDC1_SDC1 (mips_opts.arch))
        {
          s = "ldc1";
          goto ld_st;
@@ -8872,7 +9398,7 @@ macro (struct mips_cl_insn *ip)
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
-      if (mips_opts.isa != ISA_MIPS1)
+      if (CPU_HAS_LDC1_SDC1 (mips_opts.arch))
        {
          s = "sdc1";
          goto ld_st;
@@ -8880,6 +9406,16 @@ macro (struct mips_cl_insn *ip)
       s = "swc1";
       goto ldd_std;
 
+    case M_LQ_AB:
+      fmt = "t,o(b)";
+      s = "lq";
+      goto ld;
+
+    case M_SQ_AB:
+      fmt = "t,o(b)";
+      s = "sq";
+      goto ld_st;
+
     case M_LD_AB:
       fmt = "t,o(b)";
       if (HAVE_64BIT_GPRS)
@@ -8900,6 +9436,51 @@ macro (struct mips_cl_insn *ip)
       s = "sw";
 
     ldd_std:
+      /* Even on a big endian machine $fn comes before $fn+1.  We have
+        to adjust when loading from memory.  We set coproc if we must
+        load $fn+1 first.  */
+      /* Itbl support may require additional care here.  */
+      if (!target_big_endian)
+       coproc = 0;
+
+      if (small_offset_p (0, align, 16))
+       {
+         ep = &offset_expr;
+         if (!small_offset_p (4, align, 16))
+           {
+             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", AT, breg,
+                          -1, offset_reloc[0], offset_reloc[1],
+                          offset_reloc[2]);
+             expr1.X_add_number = 0;
+             ep = &expr1;
+             breg = AT;
+             used_at = 1;
+             offset_reloc[0] = BFD_RELOC_LO16;
+             offset_reloc[1] = BFD_RELOC_UNUSED;
+             offset_reloc[2] = BFD_RELOC_UNUSED;
+           }
+         if (strcmp (s, "lw") == 0 && treg == breg)
+           {
+             ep->X_add_number += 4;
+             macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0],
+                          offset_reloc[1], offset_reloc[2], breg);
+             ep->X_add_number -= 4;
+             macro_build (ep, s, fmt, treg, -1, offset_reloc[0],
+                          offset_reloc[1], offset_reloc[2], breg);
+           }
+         else
+           {
+             macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1,
+                          offset_reloc[0], offset_reloc[1], offset_reloc[2],
+                          breg);
+             ep->X_add_number += 4;
+             macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1,
+                          offset_reloc[0], offset_reloc[1], offset_reloc[2],
+                          breg);
+           }
+         break;
+       }
+
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
@@ -8916,13 +9497,6 @@ macro (struct mips_cl_insn *ip)
          as_bad (_("Number (0x%s) larger than 32 bits"), value);
        }
 
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-        to adjust when loading from memory.  We set coproc if we must
-        load $fn+1 first.  */
-      /* Itbl support may require additional care here.  */
-      if (!target_big_endian)
-       coproc = 0;
-
       if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
        {
          /* If this is a reference to a GP relative symbol, we want
@@ -8975,7 +9549,15 @@ macro (struct mips_cl_insn *ip)
              offset_expr.X_add_number -= 4;
            }
          used_at = 1;
-         macro_build_lui (&offset_expr, AT);
+         if (offset_high_part (offset_expr.X_add_number, 16)
+             != offset_high_part (offset_expr.X_add_number + 4, 16))
+           {
+             load_address (AT, &offset_expr, &used_at);
+             offset_expr.X_op = O_constant;
+             offset_expr.X_add_number = 0;
+           }
+         else
+           macro_build_lui (&offset_expr, AT);
          if (breg != 0)
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
          /* Itbl support may require additional care here.  */
@@ -9115,38 +9697,15 @@ macro (struct mips_cl_insn *ip)
        abort ();
 
       break;
-
-    case M_LD_OB:
-      s = HAVE_64BIT_GPRS ? "ld" : "lw";
-      goto sd_ob;
-    case M_SD_OB:
-      s = HAVE_64BIT_GPRS ? "sd" : "sw";
-    sd_ob:
-      macro_build (&offset_expr, s, "t,o(b)", treg,
-                  -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
-                  breg);
-      if (!HAVE_64BIT_GPRS)
-       {
-         offset_expr.X_add_number += 4;
-         macro_build (&offset_expr, s, "t,o(b)", treg + 1,
-                      -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
-                      breg);
-       }
-      break;
-
        
     case M_SAA_AB:
-      ab = 1;
-    case M_SAA_OB:
       s = "saa";
-      off0 = 1;
+      offbits = 0;
       fmt = "t,(b)";
       goto ld_st;
     case M_SAAD_AB:
-      ab = 1;
-    case M_SAAD_OB:
       s = "saad";
-      off0 = 1;
+      offbits = 0;
       fmt = "t,(b)";
       goto ld_st;
 
@@ -9180,28 +9739,38 @@ macro (struct mips_cl_insn *ip)
       s = "c3";
     copz:
       gas_assert (!mips_opts.micromips);
-      if (NO_ISA_COP (mips_opts.arch)
-         && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
-       {
-         as_bad (_("Opcode not supported on this processor: %s"),
-                 mips_cpu_info_from_arch (mips_opts.arch)->name);
-         break;
-       }
-
       /* For now we just do C (same as Cz).  The parameter will be
          stored in insn_opcode by mips_ip.  */
-      macro_build (NULL, s, "C", ip->insn_opcode);
+      macro_build (NULL, s, "C", (int) ip->insn_opcode);
       break;
 
     case M_MOVE:
       move_register (dreg, sreg);
       break;
 
+    case M_MOVEP:
+      gas_assert (mips_opts.micromips);
+      gas_assert (mips_opts.insn32);
+      dreg = micromips_to_32_reg_h_map1[EXTRACT_OPERAND (1, MH, *ip)];
+      breg = micromips_to_32_reg_h_map2[EXTRACT_OPERAND (1, MH, *ip)];
+      sreg = micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
+      treg = micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
+      move_register (dreg, sreg);
+      move_register (breg, treg);
+      break;
+
     case M_DMUL:
       dbl = 1;
     case M_MUL:
+      if (mips_opts.arch == CPU_R5900)
+        {
+          macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", dreg, sreg, treg);
+        }
+      else
+        {
       macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
       macro_build (NULL, "mflo", MFHL_FMT, dreg);
+        }
       break;
 
     case M_DMUL_I:
@@ -9790,89 +10359,69 @@ macro (struct mips_cl_insn *ip)
       end_noreorder ();
       break;
 
-    case M_ULH_A:
-      ab = 1;
-    case M_ULH:
+    case M_ULH_AB:
       s = "lb";
       s2 = "lbu";
       off = 1;
       goto uld_st;
-    case M_ULHU_A:
-      ab = 1;
-    case M_ULHU:
+    case M_ULHU_AB:
       s = "lbu";
       s2 = "lbu";
       off = 1;
       goto uld_st;
-    case M_ULW_A:
-      ab = 1;
-    case M_ULW:
+    case M_ULW_AB:
       s = "lwl";
       s2 = "lwr";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       off = 3;
       goto uld_st;
-    case M_ULD_A:
-      ab = 1;
-    case M_ULD:
+    case M_ULD_AB:
       s = "ldl";
       s2 = "ldr";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       off = 7;
       goto uld_st;
-    case M_USH_A:
-      ab = 1;
-    case M_USH:
+    case M_USH_AB:
       s = "sb";
       s2 = "sb";
       off = 1;
       ust = 1;
       goto uld_st;
-    case M_USW_A:
-      ab = 1;
-    case M_USW:
+    case M_USW_AB:
       s = "swl";
       s2 = "swr";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       off = 3;
       ust = 1;
       goto uld_st;
-    case M_USD_A:
-      ab = 1;
-    case M_USD:
+    case M_USD_AB:
       s = "sdl";
       s2 = "sdr";
-      off12 = mips_opts.micromips;
+      offbits = (mips_opts.micromips ? 12 : 16);
       off = 7;
       ust = 1;
 
     uld_st:
-      if (!ab && offset_expr.X_add_number >= 0x8000 - off)
-       as_bad (_("Operand overflow"));
-
+      large_offset = !small_offset_p (off, align, offbits);
       ep = &offset_expr;
       expr1.X_add_number = 0;
-      if (ab)
-       {
-         used_at = 1;
-         tempreg = AT;
-         load_address (tempreg, ep, &used_at);
-         if (breg != 0)
-           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-                        tempreg, tempreg, breg);
-         breg = tempreg;
-         tempreg = treg;
-         ep = &expr1;
-       }
-      else if (off12
-              && (offset_expr.X_op != O_constant
-                  || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number)
-                  || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number + off)))
+      if (large_offset)
        {
          used_at = 1;
          tempreg = AT;
-         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg,
-                      -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
+         if (small_offset_p (0, align, 16))
+           macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg, -1,
+                        offset_reloc[0], offset_reloc[1], offset_reloc[2]);
+         else
+           {
+             load_address (tempreg, ep, &used_at);
+             if (breg != 0)
+               macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+                            tempreg, tempreg, breg);
+           }
+         offset_reloc[0] = BFD_RELOC_LO16;
+         offset_reloc[1] = BFD_RELOC_UNUSED;
+         offset_reloc[2] = BFD_RELOC_UNUSED;
          breg = tempreg;
          tempreg = treg;
          ep = &expr1;
@@ -9890,21 +10439,22 @@ macro (struct mips_cl_insn *ip)
 
       if (!target_big_endian)
        ep->X_add_number += off;
-      if (!off12)
-       macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+      if (offbits == 12)
+       macro_build (NULL, s, "t,~(b)", tempreg, (int) ep->X_add_number, breg);
       else
-       macro_build (NULL, s, "t,~(b)",
-                    tempreg, (unsigned long) ep->X_add_number, breg);
+       macro_build (ep, s, "t,o(b)", tempreg, -1,
+                    offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       if (!target_big_endian)
        ep->X_add_number -= off;
       else
        ep->X_add_number += off;
-      if (!off12)
-       macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
-      else
+      if (offbits == 12)
        macro_build (NULL, s2, "t,~(b)",
-                    tempreg, (unsigned long) ep->X_add_number, breg);
+                    tempreg, (int) ep->X_add_number, breg);
+      else
+       macro_build (ep, s2, "t,o(b)", tempreg, -1,
+                    offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* If necessary, move the result in tempreg to the final destination.  */
       if (!ust && treg != tempreg)
@@ -9919,14 +10469,15 @@ macro (struct mips_cl_insn *ip)
       used_at = 1;
       if (target_big_endian == ust)
        ep->X_add_number += off;
-      tempreg = ust || ab ? treg : AT;
-      macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+      tempreg = ust || large_offset ? treg : AT;
+      macro_build (ep, s, "t,o(b)", tempreg, -1,
+                  offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* For halfword transfers we need a temporary register to shuffle
          bytes.  Unfortunately for M_USH_A we have none available before
          the next store as AT holds the base address.  We deal with this
          case by clobbering TREG and then restoring it as with ULH.  */
-      tempreg = ust == ab ? treg : AT;
+      tempreg = ust == large_offset ? treg : AT;
       if (ust)
        macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
 
@@ -9934,21 +10485,23 @@ macro (struct mips_cl_insn *ip)
        ep->X_add_number -= off;
       else
        ep->X_add_number += off;
-      macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+      macro_build (ep, s2, "t,o(b)", tempreg, -1,
+                  offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* For M_USH_A re-retrieve the LSB.  */
-      if (ust && ab)
+      if (ust && large_offset)
        {
          if (target_big_endian)
            ep->X_add_number += off;
          else
            ep->X_add_number -= off;
-         macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
+         macro_build (&expr1, "lbu", "t,o(b)", AT, -1,
+                      offset_reloc[0], offset_reloc[1], offset_reloc[2], AT);
        }
       /* For ULH and M_USH_A OR the LSB in.  */
-      if (!ust || ab)
+      if (!ust || large_offset)
        {
-         tempreg = !ab ? AT : treg;
+         tempreg = !large_offset ? AT : treg;
          macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
          macro_build (NULL, "or", "d,v,t", treg, treg, AT);
        }
@@ -9991,7 +10544,7 @@ mips16_macro (struct mips_cl_insn *ip)
   switch (mask)
     {
     default:
-      internalError ();
+      abort ();
 
     case M_DDIV_3:
       dbl = 1;
@@ -10228,16 +10781,13 @@ validate_mips_insn (const struct mips_opcode *opc)
          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;
-         case 'D': USE_BITS (OP_MASK_RD,       OP_SH_RD);
-                   USE_BITS (OP_MASK_SEL,      OP_SH_SEL);     break;
          case 'E': USE_BITS (OP_MASK_SHAMT,    OP_SH_SHAMT);   break;
          case 'F': USE_BITS (OP_MASK_INSMSB,   OP_SH_INSMSB);  break;
          case 'G': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
          case 'H': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
          case 'I': break;
+         case 'J': USE_BITS (OP_MASK_CODE10,   OP_SH_CODE10);  break;
          case 't': USE_BITS (OP_MASK_RT,       OP_SH_RT);      break;
-         case 'T': USE_BITS (OP_MASK_RT,       OP_SH_RT);
-                   USE_BITS (OP_MASK_SEL,      OP_SH_SEL);     break;
          case 'x': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
          case 'X': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
          case 'p': USE_BITS (OP_MASK_CINSPOS,  OP_SH_CINSPOS); break;
@@ -10250,6 +10800,8 @@ validate_mips_insn (const struct mips_opcode *opc)
          case 'a': USE_BITS (OP_MASK_OFFSET_A, OP_SH_OFFSET_A); break;
          case 'b': USE_BITS (OP_MASK_OFFSET_B, OP_SH_OFFSET_B); break;
          case 'c': USE_BITS (OP_MASK_OFFSET_C, OP_SH_OFFSET_C); break;
+         case 'i': USE_BITS (OP_MASK_TARGET,   OP_SH_TARGET);  break;
+         case 'j': USE_BITS (OP_MASK_EVAOFFSET, OP_SH_EVAOFFSET); break;
 
          default:
            as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
@@ -10310,9 +10862,7 @@ validate_mips_insn (const struct mips_opcode *opc)
                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;
-      case '1':        USE_BITS (OP_MASK_SHAMT,        OP_SH_SHAMT);   break;
+      case '1': USE_BITS (OP_MASK_STYPE,       OP_SH_STYPE);   break;
       case '2': USE_BITS (OP_MASK_BP,          OP_SH_BP);      break;
       case '3': USE_BITS (OP_MASK_SA3,         OP_SH_SA3);     break;
       case '4': USE_BITS (OP_MASK_SA4,         OP_SH_SA4);     break;
@@ -10406,11 +10956,12 @@ validate_micromips_insn (const struct mips_opcode *opc)
          case 'A': USE_BITS (EXTLSB);  break;
          case 'B': USE_BITS (INSMSB);  break;
          case 'C': USE_BITS (EXTMSBD); break;
-         case 'D': USE_BITS (RS);      USE_BITS (SEL); break;
          case 'E': USE_BITS (EXTLSB);  break;
          case 'F': USE_BITS (INSMSB);  break;
          case 'G': USE_BITS (EXTMSBD); break;
          case 'H': USE_BITS (EXTMSBD); break;
+         case 'i': USE_BITS (TARGET);  break;
+         case 'j': USE_BITS (EVAOFFSET);       break;
          default:
            as_bad (_("Internal error: bad mips opcode "
                      "(unknown extension operand type `%c%c'): %s %s"),
@@ -10451,7 +11002,6 @@ validate_micromips_insn (const struct mips_opcode *opc)
          case 'f': USE_BITS (MF);      break;
          case 'g': USE_BITS (MG);      break;
          case 'h': USE_BITS (MH);      break;
-         case 'i': USE_BITS (MI);      break;
          case 'j': USE_BITS (MJ);      break;
          case 'l': USE_BITS (ML);      break;
          case 'm': USE_BITS (MM);      break;
@@ -10473,8 +11023,17 @@ validate_micromips_insn (const struct mips_opcode *opc)
        break;
       case '.': USE_BITS (OFFSET10);   break;
       case '1': USE_BITS (STYPE);      break;
+      case '2': USE_BITS (BP);         break;
+      case '3': USE_BITS (SA3);                break;
+      case '4': USE_BITS (SA4);                break;
+      case '5': USE_BITS (IMM8);       break;
+      case '6': USE_BITS (RS);         break;
+      case '7': USE_BITS (DSPACC);     break;
+      case '8': USE_BITS (WRDSP);      break;
+      case '0': USE_BITS (DSPSFT);     break;
       case '<': USE_BITS (SHAMT);      break;
       case '>': USE_BITS (SHAMT);      break;
+      case '@': USE_BITS (IMM10);      break;
       case 'B': USE_BITS (CODE10);     break;
       case 'C': USE_BITS (COPZ);       break;
       case 'D': USE_BITS (FD);         break;
@@ -10489,6 +11048,7 @@ validate_micromips_insn (const struct mips_opcode *opc)
       case 'T': USE_BITS (FT);         break;
       case 'V': USE_BITS (FS);         break;
       case '\\': USE_BITS (3BITPOS);   break;
+      case '^': USE_BITS (RD);         break;
       case 'a': USE_BITS (TARGET);     break;
       case 'b': USE_BITS (RS);         break;
       case 'c': USE_BITS (CODE);       break;
@@ -10559,7 +11119,7 @@ mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
     /* Let a macro pass, we'll catch it later when it is expanded.  */
     return 1;
 
-  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa))
+  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa) || (mips_opts.arch == CPU_R5900))
     {
       /* Allow odd registers for single-precision ops.  */
       switch (insn->pinfo & (FP_S | FP_D))
@@ -10600,10 +11160,12 @@ expr_const_in_range (expressionS *ep, offsetT min, offsetT max, int bit)
          && ep->X_add_number < max << bit);
 }
 
-/* This routine assembles an instruction into its binary format.  As a
-   side effect, it sets one of the global variables imm_reloc or
-   offset_reloc to the type of relocation to do if one of the operands
-   is an address expression.  */
+/* Assemble an instruction into its binary format.  If the instruction
+   is a macro, set imm_expr, imm2_expr and offset_expr to the values
+   associated with "I", "+I" and "A" operands respectively.  Otherwise
+   store the value of the relocatable field (if any) in offset_expr.
+   In both cases set offset_reloc to the relocation operators applied
+   to offset_expr.  */
 
 static void
 mips_ip (char *str, struct mips_cl_insn *ip)
@@ -10618,11 +11180,12 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   char c = 0;
   struct mips_opcode *insn;
   char *argsStart;
-  unsigned int regno;
+  unsigned int regno, regno2;
   unsigned int lastregno;
   unsigned int destregno = 0;
   unsigned int lastpos = 0;
   unsigned int limlo, limhi;
+  int sizelo;
   char *s_reset;
   offsetT min_range, max_range;
   long opend;
@@ -10735,6 +11298,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
            sprintf (buf, _("Opcode not supported on this processor: %s (%s)"),
                     mips_cpu_info_from_arch (mips_opts.arch)->name,
                     mips_cpu_info_from_isa (mips_opts.isa)->name);
+         else if (mips_opts.insn32)
+           sprintf (buf, _("Opcode not supported in the `insn32' mode"));
          else
            sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
                     8 * forced_insn_length);
@@ -10743,6 +11308,13 @@ mips_ip (char *str, struct mips_cl_insn *ip)
          return;
        }
 
+      imm_expr.X_op = O_absent;
+      imm2_expr.X_op = O_absent;
+      offset_expr.X_op = O_absent;
+      offset_reloc[0] = BFD_RELOC_UNUSED;
+      offset_reloc[1] = BFD_RELOC_UNUSED;
+      offset_reloc[2] = BFD_RELOC_UNUSED;
+
       create_insn (ip, insn);
       insn_error = NULL;
       argnum = 1;
@@ -10760,8 +11332,9 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                return;
              break;
 
-           case '2': /* DSP 2-bit unsigned immediate in bit 11.  */
-             gas_assert (!mips_opts.micromips);
+           case '2':
+             /* DSP 2-bit unsigned immediate in bit 11 (for standard MIPS
+                code) or 14 (for microMIPS code).  */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number != 1
@@ -10770,100 +11343,127 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
                          (unsigned long) imm_expr.X_add_number);
                }
-             INSERT_OPERAND (0, BP, *ip, imm_expr.X_add_number);
+             INSERT_OPERAND (mips_opts.micromips,
+                             BP, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
-           case '3': /* DSP 3-bit unsigned immediate in bit 21.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if (imm_expr.X_add_number & ~OP_MASK_SA3)
-               {
-                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
-                         OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, SA3, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+           case '3':
+             /* DSP 3-bit unsigned immediate in bit 21 (for standard MIPS
+                code) or 13 (for microMIPS code).  */
+             {
+               unsigned long mask = (mips_opts.micromips
+                                     ? MICROMIPSOP_MASK_SA3 : OP_MASK_SA3);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               if ((unsigned long) imm_expr.X_add_number > mask)
+                 as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+                         mask, (unsigned long) imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               SA3, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
-           case '4': /* DSP 4-bit unsigned immediate in bit 21.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if (imm_expr.X_add_number & ~OP_MASK_SA4)
-               {
-                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
-                         OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, SA4, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+           case '4':
+             /* DSP 4-bit unsigned immediate in bit 21 (for standard MIPS
+                code) or 12 (for microMIPS code).  */
+             {
+               unsigned long mask = (mips_opts.micromips
+                                     ? MICROMIPSOP_MASK_SA4 : OP_MASK_SA4);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               if ((unsigned long) imm_expr.X_add_number > mask)
+                 as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+                         mask, (unsigned long) imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               SA4, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
-           case '5': /* DSP 8-bit unsigned immediate in bit 16.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if (imm_expr.X_add_number & ~OP_MASK_IMM8)
-               {
-                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
-                         OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, IMM8, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+           case '5':
+             /* DSP 8-bit unsigned immediate in bit 16 (for standard MIPS
+                code) or 13 (for microMIPS code).  */
+             {
+               unsigned long mask = (mips_opts.micromips
+                                     ? MICROMIPSOP_MASK_IMM8 : OP_MASK_IMM8);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               if ((unsigned long) imm_expr.X_add_number > mask)
+                 as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+                         mask, (unsigned long) imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               IMM8, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
-           case '6': /* DSP 5-bit unsigned immediate in bit 21.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if (imm_expr.X_add_number & ~OP_MASK_RS)
-               {
-                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
-                         OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, RS, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+           case '6':
+             /* DSP 5-bit unsigned immediate in bit 21 (for standard MIPS
+                code) or 16 (for microMIPS code).  */
+             {
+               unsigned long mask = (mips_opts.micromips
+                                     ? MICROMIPSOP_MASK_RS : OP_MASK_RS);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               if ((unsigned long) imm_expr.X_add_number > mask)
+                 as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+                         mask, (unsigned long) imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               RS, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
-           case '7': /* Four DSP accumulators in bits 11,12.  */
-             gas_assert (!mips_opts.micromips);
-             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
-                 s[3] >= '0' && s[3] <= '3')
+           case '7':
+             /* Four DSP accumulators in bit 11 (for standard MIPS code)
+                or 14 (for microMIPS code).  */
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c'
+                 && s[3] >= '0' && s[3] <= '3')
                {
                  regno = s[3] - '0';
                  s += 4;
-                 INSERT_OPERAND (0, DSPACC, *ip, regno);
+                 INSERT_OPERAND (mips_opts.micromips, DSPACC, *ip, regno);
                  continue;
                }
              else
                as_bad (_("Invalid dsp acc register"));
              break;
 
-           case '8': /* DSP 6-bit unsigned immediate in bit 11.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
-               {
-                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
-                         OP_MASK_WRDSP,
-                         (unsigned long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, WRDSP, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+           case '8':
+             /* DSP 6-bit unsigned immediate in bit 11 (for standard MIPS
+                code) or 14 (for microMIPS code).  */
+             {
+               unsigned long mask = (mips_opts.micromips
+                                     ? MICROMIPSOP_MASK_WRDSP
+                                     : OP_MASK_WRDSP);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               if ((unsigned long) imm_expr.X_add_number > mask)
+                 as_bad (_("DSP immediate not in range 0..%lu (%lu)"),
+                         mask, (unsigned long) imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               WRDSP, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
            case '9': /* Four DSP accumulators in bits 21,22.  */
              gas_assert (!mips_opts.micromips);
-             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
-                 s[3] >= '0' && s[3] <= '3')
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c'
+                 && s[3] >= '0' && s[3] <= '3')
                {
                  regno = s[3] - '0';
                  s += 4;
@@ -10874,22 +11474,27 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                as_bad (_("Invalid dsp acc register"));
              break;
 
-           case '0': /* DSP 6-bit signed immediate in bit 20.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             min_range = -((OP_MASK_DSPSFT + 1) >> 1);
-             max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
-             if (imm_expr.X_add_number < min_range ||
-                 imm_expr.X_add_number > max_range)
-               {
+           case '0':
+             /* DSP 6-bit signed immediate in bit 20 (for standard MIPS
+                code) or 16 (for microMIPS code).  */
+             {
+               long mask = (mips_opts.micromips
+                            ? MICROMIPSOP_MASK_DSPSFT : OP_MASK_DSPSFT);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               min_range = -((mask + 1) >> 1);
+               max_range = ((mask + 1) >> 1) - 1;
+               if (imm_expr.X_add_number < min_range
+                   || imm_expr.X_add_number > max_range)
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                          (long) min_range, (long) max_range,
                          (long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, DSPSFT, *ip, imm_expr.X_add_number);
-             imm_expr.X_op = O_absent;
-             s = expr_end;
+               INSERT_OPERAND (mips_opts.micromips,
+                               DSPSFT, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
              continue;
 
            case '\'': /* DSP 6-bit unsigned immediate in bit 16.  */
@@ -10926,19 +11531,35 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case '@': /* DSP 10-bit signed immediate in bit 16.  */
-             gas_assert (!mips_opts.micromips);
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             min_range = -((OP_MASK_IMM10 + 1) >> 1);
-             max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
-             if (imm_expr.X_add_number < min_range ||
-                 imm_expr.X_add_number > max_range)
-               {
+             {
+               long mask = (mips_opts.micromips
+                            ? MICROMIPSOP_MASK_IMM10 : OP_MASK_IMM10);
+
+               my_getExpression (&imm_expr, s);
+               check_absolute_expr (ip, &imm_expr);
+               min_range = -((mask + 1) >> 1);
+               max_range = ((mask + 1) >> 1) - 1;
+               if (imm_expr.X_add_number < min_range
+                   || imm_expr.X_add_number > max_range)
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                          (long) min_range, (long) max_range,
                          (long) imm_expr.X_add_number);
-               }
-             INSERT_OPERAND (0, IMM10, *ip, imm_expr.X_add_number);
+               INSERT_OPERAND (mips_opts.micromips,
+                               IMM10, *ip, imm_expr.X_add_number);
+               imm_expr.X_op = O_absent;
+               s = expr_end;
+             }
+             continue;
+
+           case '^': /* DSP 5-bit unsigned immediate in bit 11.  */
+             gas_assert (mips_opts.micromips);
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~MICROMIPSOP_MASK_RD)
+               as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                       MICROMIPSOP_MASK_RD,
+                       (unsigned long) imm_expr.X_add_number);
+             INSERT_OPERAND (1, RD, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -11061,13 +11682,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                continue;
              break;
 
-           case '[':           /* These must match exactly.  */
-           case ']':
-             gas_assert (!mips_opts.micromips);
-             if (*s++ == *args)
-               continue;
-             break;
-
            case '+':           /* Opcode extension character.  */
              switch (*++args)
                {
@@ -11082,7 +11696,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                    while (imm->type && imm->type != *args)
                      ++imm;
                    if (! imm->type)
-                     internalError ();
+                     abort ();
                    my_getExpression (&imm_expr, s);
                    check_absolute_expr (ip, &imm_expr);
                    if ((unsigned long) imm_expr.X_add_number & ~imm->mask)
@@ -11100,6 +11714,23 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  }
                  continue;
 
+               case 'J':               /* 10-bit hypcall code.  */
+                 gas_assert (!mips_opts.micromips);
+                 {
+                   unsigned long mask = OP_MASK_CODE10;
+
+                   my_getExpression (&imm_expr, s);
+                   check_absolute_expr (ip, &imm_expr);
+                   if ((unsigned long) imm_expr.X_add_number > mask)
+                     as_warn (_("Code for %s not in range 0..%lu (%lu)"),
+                              ip->insn_mo->name,
+                              mask, (unsigned long) imm_expr.X_add_number);
+                   INSERT_OPERAND (0, CODE10, *ip, imm_expr.X_add_number);
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                 }
+                 continue;
+
                case 'A':               /* ins/ext position, becomes LSB.  */
                  limlo = 0;
                  limhi = 31;
@@ -11160,23 +11791,25 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                case 'C':               /* ext size, becomes MSBD.  */
                  limlo = 1;
                  limhi = 32;
+                 sizelo = 1;
                  goto do_msbd;
                case 'G':
                  limlo = 33;
                  limhi = 64;
+                 sizelo = 33;
                  goto do_msbd;
                case 'H':
                  limlo = 33;
                  limhi = 64;
+                 sizelo = 1;
                  goto do_msbd;
                do_msbd:
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
-                 /* Check for negative input so that small negative numbers
-                    will not succeed incorrectly.  The checks against
-                    (pos+size) transitively check "size" itself,
-                    assuming that "pos" is reasonable.  */
-                 if ((long) imm_expr.X_add_number < 0
+                 /* The checks against (pos+size) don't transitively check
+                    "size" itself, assuming that "pos" is reasonable.
+                    We also need to check the lower bound of "size".  */
+                 if ((long) imm_expr.X_add_number < sizelo
                      || ((unsigned long) imm_expr.X_add_number
                          + lastpos) < limlo
                      || ((unsigned long) imm_expr.X_add_number
@@ -11193,10 +11826,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  s = expr_end;
                  continue;
 
-               case 'D':
-                 /* +D is for disassembly only; never match.  */
-                 break;
-
                case 'I':
                  /* "+I" is like "I", except that imm2_expr is used.  */
                  my_getExpression (&imm2_expr, s);
@@ -11208,11 +11837,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  s = expr_end;
                  continue;
 
-               case 'T': /* Coprocessor register.  */
-                 gas_assert (!mips_opts.micromips);
-                 /* +T is for disassembly only; never match.  */
-                 break;
-
                case 't': /* Coprocessor register number.  */
                  gas_assert (!mips_opts.micromips);
                  if (s[0] == '$' && ISDIGIT (s[1]))
@@ -11282,8 +11906,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                    }
-                 /* Make the pos explicit to simplify +S.  */
-                 lastpos = imm_expr.X_add_number + 32;
+                 lastpos = imm_expr.X_add_number;
                  INSERT_OPERAND (0, CINSPOS, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  s = expr_end;
@@ -11305,11 +11928,12 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  continue;
 
                case 's':
-                 /* cins and exts length-minus-one field.  */
+                 /* cins32 and exts32 length-minus-one field.  */
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
-                 if ((unsigned long) imm_expr.X_add_number > 31)
+                 if ((unsigned long) imm_expr.X_add_number > 31
+                     || (unsigned long) imm_expr.X_add_number + lastpos > 31)
                    {
                      as_bad (_("Improper size (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
@@ -11321,12 +11945,11 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  continue;
 
                case 'S':
-                 /* cins32/exts32 and cins/exts aliasing cint32/exts32
-                    length-minus-one field.  */
+                 /* cins/exts length-minus-one field.  */
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
-                 if ((long) imm_expr.X_add_number < 0
+                 if ((unsigned long) imm_expr.X_add_number > 31
                      || (unsigned long) imm_expr.X_add_number + lastpos > 63)
                    {
                      as_bad (_("Improper size (%lu)"),
@@ -11441,6 +12064,40 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  INSERT_OPERAND (0, FZ, *ip, regno);
                  continue;
 
+               case 'i':
+                 goto jump;
+
+               case 'j':
+                 {
+                   int shift = 8;
+                   size_t i;
+                   bfd_reloc_code_real_type r[3];
+
+                   /* Check whether there is only a single bracketed expression
+                      left.  If so, it must be the base register and the
+                      constant must be zero.  */
+                   if (*s == '(' && strchr (s + 1, '(') == 0)
+                     continue;
+
+                   /* If this value won't fit into the offset, then go find
+                      a macro that will generate a 16- or 32-bit offset code
+                      pattern.  */
+                   i = my_getSmallExpression (&imm_expr, r, s);
+                   if ((i == 0 && (imm_expr.X_op != O_constant
+                                   || imm_expr.X_add_number >= 1 << shift
+                                   || imm_expr.X_add_number < -1 << shift))
+                       || i > 0)
+                     {
+                       imm_expr.X_op = O_absent;
+                       break;
+                     }
+                   INSERT_OPERAND (mips_opts.micromips, EVAOFFSET, *ip,
+                                   imm_expr.X_add_number);
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                 }
+                 continue;
+
                default:
                  as_bad (_("Internal error: bad %s opcode "
                            "(unknown extension operand type `+%c'): %s %s"),
@@ -11457,6 +12114,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              {
                int shift = *args == '.' ? 9 : 11;
                size_t i;
+               bfd_reloc_code_real_type r[3];
 
                /* Check whether there is only a single bracketed expression
                   left.  If so, it must be the base register and the
@@ -11467,7 +12125,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                /* If this value won't fit into the offset, then go find
                   a macro that will generate a 16- or 32-bit offset code
                   pattern.  */
-               i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+               i = my_getSmallExpression (&imm_expr, r, s);
                if ((i == 0 && (imm_expr.X_op != O_constant
                                || imm_expr.X_add_number >= 1 << shift
                                || imm_expr.X_add_number < -1 << shift))
@@ -11663,6 +12321,10 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                as_warn (_("Invalid performance register (%lu)"),
                         (unsigned long) imm_expr.X_add_number);
+             if (imm_expr.X_add_number != 0 && mips_opts.arch == CPU_R5900
+               && (!strcmp(insn->name,"mfps") || !strcmp(insn->name,"mtps")))
+               as_warn (_("Invalid performance register (%lu)"),
+                 (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (0, PERFREG, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
@@ -11887,7 +12549,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
            case 'X':           /* MDMX destination register.  */
            case 'Y':           /* MDMX source register.  */
            case 'Z':           /* MDMX target register.  */
-             is_mdmx = 1;
+             is_mdmx = !(insn->membership & INSN_5400);
            case 'W':
              gas_assert (!mips_opts.micromips);
            case 'D':           /* Floating point destination register.  */
@@ -11897,7 +12559,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
            case 'V':
              rtype = RTYPE_FPU;
              if (is_mdmx
-                 || (mips_opts.ase_mdmx
+                 || ((mips_opts.ase & ASE_MDMX)
                      && (ip->insn_mo->pinfo & FP_D)
                      && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
                                                | INSN_COPROC_MEMORY_DELAY
@@ -11943,6 +12605,11 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                      /* This is like 'Z', but also needs to fix the MDMX
                         vector/scalar select bits.  Note that the
                         scalar immediate case is handled above.  */
+                     if ((ip->insn_mo->membership & INSN_5400)
+                         && strcmp (insn->name, "rzu.ob") == 0)
+                       as_bad (_("Operand %d of `%s' must be an immediate"),
+                               argnum, ip->insn_mo->name);
+
                      if (*s == '[')
                        {
                          int is_qh = (ip->insn_opcode & (1 << OP_SH_VSEL));
@@ -11965,7 +12632,13 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                            s++;
                        }
                      else
-                        {
+                       {
+                         if ((ip->insn_mo->membership & INSN_5400)
+                             && (strcmp (insn->name, "sll.ob") == 0
+                                 || strcmp (insn->name, "srl.ob") == 0))
+                           as_bad (_("Operand %d of `%s' must be scalar"),
+                                   argnum, ip->insn_mo->name);
+
                           if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
                             ip->insn_opcode |= (MDMX_FMTSEL_VEC_QH
                                                << OP_SH_VSEL);
@@ -12011,10 +12684,20 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case 'A':
-             my_getExpression (&offset_expr, s);
-             normalize_address_expr (&offset_expr);
-             *imm_reloc = BFD_RELOC_32;
-             s = expr_end;
+             my_getSmallExpression (&offset_expr, offset_reloc, s);
+             if (offset_expr.X_op == O_register)
+               {
+                 /* Assume that the offset has been elided and that what
+                    we saw was a base register.  The match will fail later
+                    if that assumption turns out to be wrong.  */
+                 offset_expr.X_op = O_constant;
+                 offset_expr.X_add_number = 0;
+               }
+             else
+               {
+                 normalize_address_expr (&offset_expr);
+                 s = expr_end;
+               }
              continue;
 
            case 'F':
@@ -12123,7 +12806,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        if (offset_expr.X_add_number == 0)
                          offset_expr.X_op = O_absent;
                      }
-                   else if (sizeof (imm_expr.X_add_number) > 4)
+                   else
                      {
                        imm_expr.X_op = O_constant;
                        if (!target_big_endian)
@@ -12131,25 +12814,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        else
                          imm_expr.X_add_number = bfd_getb64 (temp);
                      }
-                   else
-                     {
-                       imm_expr.X_op = O_big;
-                       imm_expr.X_add_number = 4;
-                       if (!target_big_endian)
-                         {
-                           generic_bignum[0] = bfd_getl16 (temp);
-                           generic_bignum[1] = bfd_getl16 (temp + 2);
-                           generic_bignum[2] = bfd_getl16 (temp + 4);
-                           generic_bignum[3] = bfd_getl16 (temp + 6);
-                         }
-                       else
-                         {
-                           generic_bignum[0] = bfd_getb16 (temp + 6);
-                           generic_bignum[1] = bfd_getb16 (temp + 4);
-                           generic_bignum[2] = bfd_getb16 (temp + 2);
-                           generic_bignum[3] = bfd_getb16 (temp);
-                         }
-                     }
                  }
                else
                  {
@@ -12176,14 +12840,13 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
                      }
                    new_seg = subseg_new (newname, (subsegT) 0);
-                   if (IS_ELF)
-                     bfd_set_section_flags (stdoutput, new_seg,
-                                            (SEC_ALLOC
-                                             | SEC_LOAD
-                                             | SEC_READONLY
-                                             | SEC_DATA));
+                   bfd_set_section_flags (stdoutput, new_seg,
+                                          (SEC_ALLOC
+                                           | SEC_LOAD
+                                           | SEC_READONLY
+                                           | SEC_DATA));
                    frag_align (*args == 'l' ? 2 : 3, 0, 0);
-                   if (IS_ELF && strncmp (TARGET_OS, "elf", 3) != 0)
+                   if (strncmp (TARGET_OS, "elf", 3) != 0)
                      record_alignment (new_seg, 4);
                    else
                      record_alignment (new_seg, *args == 'l' ? 2 : 3);
@@ -12208,8 +12871,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
            case 'i':           /* 16-bit unsigned immediate.  */
            case 'j':           /* 16-bit signed immediate.  */
-             *imm_reloc = BFD_RELOC_LO16;
-             if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
+             *offset_reloc = BFD_RELOC_LO16;
+             if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0)
                {
                  int more;
                  offsetT minval, maxval;
@@ -12217,18 +12880,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  more = (insn + 1 < past
                          && strcmp (insn->name, insn[1].name) == 0);
 
-                 /* If the expression was written as an unsigned number,
-                    only treat it as signed if there are no more
-                    alternatives.  */
-                 if (more
-                     && *args == 'j'
-                     && sizeof (imm_expr.X_add_number) <= 4
-                     && imm_expr.X_op == O_constant
-                     && imm_expr.X_add_number < 0
-                     && imm_expr.X_unsigned
-                     && HAVE_64BIT_GPRS)
-                   break;
-
                  /* For compatibility with older assemblers, we accept
                     0x8000-0xffff as signed 16-bit numbers when only
                     signed numbers are allowed.  */
@@ -12239,14 +12890,14 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                  else
                    minval = -0x8000, maxval = 0xffff;
 
-                 if (imm_expr.X_op != O_constant
-                     || imm_expr.X_add_number < minval
-                     || imm_expr.X_add_number > maxval)
+                 if (offset_expr.X_op != O_constant
+                     || offset_expr.X_add_number < minval
+                     || offset_expr.X_add_number > maxval)
                    {
                      if (more)
                        break;
-                     if (imm_expr.X_op == O_constant
-                         || imm_expr.X_op == O_big)
+                     if (offset_expr.X_op == O_constant
+                         || offset_expr.X_op == O_big)
                        as_bad (_("Expression out of range"));
                    }
                }
@@ -12287,16 +12938,18 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case 'u':           /* Upper 16 bits.  */
-             if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
-                 && imm_expr.X_op == O_constant
-                 && (imm_expr.X_add_number < 0
-                     || imm_expr.X_add_number >= 0x10000))
+             *offset_reloc = BFD_RELOC_LO16;
+             if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0
+                 && offset_expr.X_op == O_constant
+                 && (offset_expr.X_add_number < 0
+                     || offset_expr.X_add_number >= 0x10000))
                as_bad (_("lui expression (%lu) not in range 0..65535"),
-                       (unsigned long) imm_expr.X_add_number);
+                       (unsigned long) offset_expr.X_add_number);
              s = expr_end;
              continue;
 
            case 'a':           /* 26-bit address.  */
+           jump:
              *offset_reloc = BFD_RELOC_MIPS_JMP;
              my_getExpression (&offset_expr, s);
              s = expr_end;
@@ -12408,7 +13061,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                case 'f':
                case 'g':
                case 'h':
-               case 'i':
                case 'j':
                case 'l':
                case 'm':
@@ -12531,47 +13183,32 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      case 'h':
-                       regno = mips32_to_micromips_reg_h_map[regno];
-                       break;
-
-                     case 'i':
-                       switch (EXTRACT_OPERAND (1, MI, *ip))
+                       s += strspn (s, " \t");
+                       if (*s != ',')
+                         {
+                           regno = ILLEGAL_REG;
+                           break;
+                         }
+                       ++s;
+                       s += strspn (s, " \t");
+                       ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno2);
+                       if (!ok)
+                         {
+                           regno = ILLEGAL_REG;
+                           break;
+                         }
+                       if (regno2 == AT && mips_opts.at)
                          {
-                           case 4:
-                             if (regno == 21)
-                               regno = 3;
-                             else if (regno == 22)
-                               regno = 4;
-                             else if (regno == 5)
-                               regno = 5;
-                             else if (regno == 6)
-                               regno = 6;
-                             else if (regno == 7)
-                               regno = 7;
-                             else
-                               regno = ILLEGAL_REG;
-                             break;
-
-                           case 5:
-                             if (regno == 6)
-                               regno = 0;
-                             else if (regno == 7)
-                               regno = 1;
-                             else
-                               regno = ILLEGAL_REG;
-                             break;
-
-                           case 6:
-                             if (regno == 7)
-                               regno = 2;
-                             else
-                               regno = ILLEGAL_REG;
-                             break;
-
-                           default:
-                             regno = ILLEGAL_REG;
-                             break;
+                           if (mips_opts.at == ATREG)
+                             as_warn (_("Used $at without \".set noat\""));
+                           else
+                             as_warn (_("Used $%u with \".set at=$%u\""),
+                                      regno2, mips_opts.at);
                          }
+                       regno = (mips_lookup_reg_pair
+                                (regno, regno2,
+                                 micromips_to_32_reg_h_map1,
+                                 micromips_to_32_reg_h_map2, 8));
                        break;
 
                      case 'l':
@@ -12612,7 +13249,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
 
                  if (regno == ILLEGAL_REG)
@@ -12648,10 +13285,6 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        INSERT_OPERAND (1, MH, *ip, regno);
                        break;
 
-                     case 'i':
-                       INSERT_OPERAND (1, MI, *ip, regno);
-                       break;
-
                      case 'j':
                        INSERT_OPERAND (1, MJ, *ip, regno);
                        break;
@@ -12685,7 +13318,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
                  continue;
 
@@ -13149,7 +13782,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
            default:
              as_bad (_("Bad char = '%c'\n"), *args);
-             internalError ();
+             abort ();
            }
          break;
        }
@@ -13175,12 +13808,9 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
 #define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
 
-/* This routine assembles an instruction into its binary format when
-   assembling for the mips16.  As a side effect, it sets one of the
-   global variables imm_reloc or offset_reloc to the type of relocation
-   to do if one of the operands is an address expression.  It also sets
-   forced_insn_length to the resulting instruction size in bytes if the
-   user explicitly requested a small or extended instruction.  */
+/* As for mips_ip, but used when assembling MIPS16 code.
+   Also set forced_insn_length to the resulting instruction size in
+   bytes if the user explicitly requested a small or extended instruction.  */
 
 static void
 mips16_ip (char *str, struct mips_cl_insn *ip)
@@ -13243,6 +13873,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
   for (;;)
     {
       bfd_boolean ok;
+      char relax_char;
 
       gas_assert (strcmp (insn->name, str) == 0);
 
@@ -13272,14 +13903,12 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
 
       create_insn (ip, insn);
       imm_expr.X_op = O_absent;
-      imm_reloc[0] = BFD_RELOC_UNUSED;
-      imm_reloc[1] = BFD_RELOC_UNUSED;
-      imm_reloc[2] = BFD_RELOC_UNUSED;
       imm2_expr.X_op = O_absent;
       offset_expr.X_op = O_absent;
       offset_reloc[0] = BFD_RELOC_UNUSED;
       offset_reloc[1] = BFD_RELOC_UNUSED;
       offset_reloc[2] = BFD_RELOC_UNUSED;
+      relax_char = 0;
       for (args = insn->args; 1; ++args)
        {
          int c;
@@ -13297,46 +13926,34 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            case '\0':
              if (*s == '\0')
                {
+                 offsetT value;
+
                  /* Stuff the immediate value in now, if we can.  */
-                 if (imm_expr.X_op == O_constant
-                     && *imm_reloc > BFD_RELOC_UNUSED
-                     && *imm_reloc != BFD_RELOC_MIPS16_GOT16
-                     && *imm_reloc != BFD_RELOC_MIPS16_CALL16
-                     && insn->pinfo != INSN_MACRO)
+                 if (insn->pinfo == INSN_MACRO)
                    {
-                     valueT tmp;
-
-                     switch (*offset_reloc)
-                       {
-                         case BFD_RELOC_MIPS16_HI16_S:
-                           tmp = (imm_expr.X_add_number + 0x8000) >> 16;
-                           break;
-
-                         case BFD_RELOC_MIPS16_HI16:
-                           tmp = imm_expr.X_add_number >> 16;
-                           break;
-
-                         case BFD_RELOC_MIPS16_LO16:
-                           tmp = ((imm_expr.X_add_number + 0x8000) & 0xffff)
-                                 - 0x8000;
-                           break;
-
-                         case BFD_RELOC_UNUSED:
-                           tmp = imm_expr.X_add_number;
-                           break;
-
-                         default:
-                           internalError ();
-                       }
+                     gas_assert (relax_char == 0);
+                     gas_assert (*offset_reloc == BFD_RELOC_UNUSED);
+                   }
+                 else if (relax_char
+                          && offset_expr.X_op == O_constant
+                          && calculate_reloc (*offset_reloc,
+                                              offset_expr.X_add_number,
+                                              &value))
+                   {
+                     mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
+                                   forced_insn_length, &ip->insn_opcode);
+                     offset_expr.X_op = O_absent;
                      *offset_reloc = BFD_RELOC_UNUSED;
-
-                     mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
-                                   tmp, TRUE, forced_insn_length == 2,
-                                   forced_insn_length == 4, &ip->insn_opcode,
-                                   &ip->use_extend, &ip->extend);
-                     imm_expr.X_op = O_absent;
-                     *imm_reloc = BFD_RELOC_UNUSED;
                    }
+                 else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
+                   {
+                     if (forced_insn_length == 2)
+                       as_bad (_("invalid unextended operand value"));
+                     forced_insn_length = 4;
+                     ip->insn_opcode |= MIPS16_EXTEND;
+                   }
+                 else if (relax_char)
+                   *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
 
                  return;
                }
@@ -13450,7 +14067,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  break;
 
                default:
-                 internalError ();
+                 abort ();
                }
 
              if (regno == ILLEGAL_REG)
@@ -13483,7 +14100,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
                  break;
                default:
-                 internalError ();
+                 abort ();
                }
 
              lastregno = regno;
@@ -13507,25 +14124,14 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            case 'U':
            case 'k':
            case 'K':
-             i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+             i = my_getSmallExpression (&offset_expr, offset_reloc, s);
              if (i > 0)
                {
-                 if (imm_expr.X_op != O_constant)
-                   {
-                     forced_insn_length = 4;
-                     ip->use_extend = TRUE;
-                     ip->extend = 0;
-                   }
-                 else
-                   {
-                     /* We need to relax this instruction.  */
-                     *offset_reloc = *imm_reloc;
-                     *imm_reloc = (int) BFD_RELOC_UNUSED + c;
-                   }
+                 relax_char = c;
                  s = expr_end;
                  continue;
                }
-             *imm_reloc = BFD_RELOC_UNUSED;
+             *offset_reloc = BFD_RELOC_UNUSED;
              /* Fall through.  */
            case '<':
            case '>':
@@ -13533,8 +14139,8 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            case ']':
            case '4':
            case '8':
-             my_getExpression (&imm_expr, s);
-             if (imm_expr.X_op == O_register)
+             my_getExpression (&offset_expr, s);
+             if (offset_expr.X_op == O_register)
                {
                  /* What we thought was an expression turned out to
                      be a register.  */
@@ -13544,11 +14150,11 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                      /* It looks like the expression was omitted
                         before a register indirection, which means
                         that the expression is implicitly zero.  We
-                        still set up imm_expr, so that we handle
+                        still set up offset_expr, so that we handle
                         explicit extensions correctly.  */
-                     imm_expr.X_op = O_constant;
-                     imm_expr.X_add_number = 0;
-                     *imm_reloc = (int) BFD_RELOC_UNUSED + c;
+                     offset_expr.X_op = O_constant;
+                     offset_expr.X_add_number = 0;
+                     relax_char = c;
                      continue;
                    }
 
@@ -13556,7 +14162,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                }
 
              /* We need to relax this instruction.  */
-             *imm_reloc = (int) BFD_RELOC_UNUSED + c;
+             relax_char = c;
              s = expr_end;
              continue;
 
@@ -13574,7 +14180,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                break;
 
              /* We need to relax this instruction.  */
-             *offset_reloc = (int) BFD_RELOC_UNUSED + c;
+             relax_char = c;
              s = expr_end;
              continue;
 
@@ -13590,8 +14196,19 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
-           case 'a':           /* 26 bit address */
-             my_getExpression (&offset_expr, s);
+           case 'I':
+             my_getExpression (&imm_expr, s);
+             if (imm_expr.X_op != O_big
+                 && imm_expr.X_op != O_constant)
+               insn_error = _("absolute expression required");
+             if (HAVE_32BIT_GPRS)
+               normalize_constant_expr (&imm_expr);
+             s = expr_end;
+             continue;
+
+           case 'a':           /* 26 bit address */
+           case 'i':
+             my_getExpression (&offset_expr, s);
              s = expr_end;
              *offset_reloc = BFD_RELOC_MIPS16_JMP;
              ip->insn_opcode <<= 16;
@@ -13668,7 +14285,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            case 'm':           /* Register list for save insn.  */
            case 'M':           /* Register list for restore insn.  */
              {
-               int opcode = 0;
+               int opcode = ip->insn_opcode;
                int framesz = 0, seen_framesz = 0;
                int nargs = 0, statics = 0, sregs = 0;
 
@@ -13822,11 +14439,8 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
 
                /* Finally build the instruction.  */
                if ((opcode >> 16) != 0 || framesz == 0)
-                 {
-                   ip->use_extend = TRUE;
-                   ip->extend = opcode >> 16;
-                 }
-               ip->insn_opcode |= opcode & 0x7f;
+                 opcode |= MIPS16_EXTEND;
+               ip->insn_opcode = opcode;
              }
            continue;
 
@@ -13846,7 +14460,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            default:
-             internalError ();
+             abort ();
            }
          break;
        }
@@ -13921,23 +14535,49 @@ static const struct mips16_immed_operand mips16_immed_operands[] =
 #define MIPS16_NUM_IMMED \
   (sizeof mips16_immed_operands / sizeof mips16_immed_operands[0])
 
-/* Handle a mips16 instruction with an immediate value.  This or's the
-   small immediate value into *INSN.  It sets *USE_EXTEND to indicate
-   whether an extended value is needed; if one is needed, it sets
-   *EXTEND to the value.  The argument type is TYPE.  The value is VAL.
-   If SMALL is true, an unextended opcode was explicitly requested.
-   If EXT is true, an extended opcode was explicitly requested.  If
-   WARN is true, warn if EXT does not match reality.  */
+/* Marshal immediate value VAL for an extended MIPS16 instruction.
+   NBITS is the number of significant bits in VAL.  */
+
+static unsigned long
+mips16_immed_extend (offsetT val, unsigned int nbits)
+{
+  int extval;
+  if (nbits == 16)
+    {
+      extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
+      val &= 0x1f;
+    }
+  else if (nbits == 15)
+    {
+      extval = ((val >> 11) & 0xf) | (val & 0x7f0);
+      val &= 0xf;
+    }
+  else
+    {
+      extval = ((val & 0x1f) << 6) | (val & 0x20);
+      val = 0;
+    }
+  return (extval << 16) | val;
+}
+
+/* Install immediate value VAL into MIPS16 instruction *INSN,
+   extending it if necessary.  The instruction in *INSN may
+   already be extended.
+
+   RELOC is the relocation that produced VAL, or BFD_RELOC_UNUSED
+   if none.  In the former case, VAL is a 16-bit number with no
+   defined signedness.
+
+   TYPE is the type of the immediate field.  USER_INSN_LENGTH
+   is the length that the user requested, or 0 if none.  */
 
 static void
-mips16_immed (char *file, unsigned int line, int type, offsetT val,
-             bfd_boolean warn, bfd_boolean small, bfd_boolean ext,
-             unsigned long *insn, bfd_boolean *use_extend,
-             unsigned short *extend)
+mips16_immed (char *file, unsigned int line, int type,
+             bfd_reloc_code_real_type reloc, offsetT val,
+             unsigned int user_insn_length, unsigned long *insn)
 {
   const struct mips16_immed_operand *op;
   int mintiny, maxtiny;
-  bfd_boolean needext;
 
   op = mips16_immed_operands;
   while (op->type != type)
@@ -13958,11 +14598,15 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
          mintiny = 0;
          maxtiny = (1 << op->nbits) - 1;
        }
+      if (reloc != BFD_RELOC_UNUSED)
+       val &= 0xffff;
     }
   else
     {
       mintiny = - (1 << (op->nbits - 1));
       maxtiny = (1 << (op->nbits - 1)) - 1;
+      if (reloc != BFD_RELOC_UNUSED)
+       val = SEXT_16BIT (val);
     }
 
   /* Branch offsets have an implicit 0 in the lowest bit.  */
@@ -13972,21 +14616,26 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
   if ((val & ((1 << op->shift) - 1)) != 0
       || val < (mintiny << op->shift)
       || val > (maxtiny << op->shift))
-    needext = TRUE;
-  else
-    needext = FALSE;
-
-  if (warn && ext && ! needext)
-    as_warn_where (file, line,
-                  _("extended operand requested but not required"));
-  if (small && needext)
-    as_bad_where (file, line, _("invalid unextended operand value"));
+    {
+      /* We need an extended instruction.  */
+      if (user_insn_length == 2)
+       as_bad_where (file, line, _("invalid unextended operand value"));
+      else
+       *insn |= MIPS16_EXTEND;
+    }
+  else if (user_insn_length == 4)
+    {
+      /* The operand doesn't force an unextended instruction to be extended.
+        Warn if the user wanted an extended instruction anyway.  */
+      *insn |= MIPS16_EXTEND;
+      as_warn_where (file, line,
+                    _("extended operand requested but not required"));
+    }
 
-  if (small || (! ext && ! needext))
+  if (mips16_opcode_length (*insn) == 2)
     {
       int insnval;
 
-      *use_extend = FALSE;
       insnval = ((val >> op->shift) & ((1 << op->nbits) - 1));
       insnval <<= op->op_shift;
       *insn |= insnval;
@@ -13994,41 +14643,25 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
   else
     {
       long minext, maxext;
-      int extval;
-
-      if (op->extu)
-       {
-         minext = 0;
-         maxext = (1 << op->extbits) - 1;
-       }
-      else
-       {
-         minext = - (1 << (op->extbits - 1));
-         maxext = (1 << (op->extbits - 1)) - 1;
-       }
-      if (val < minext || val > maxext)
-       as_bad_where (file, line,
-                     _("operand value out of range for instruction"));
 
-      *use_extend = TRUE;
-      if (op->extbits == 16)
+      if (reloc == BFD_RELOC_UNUSED)
        {
-         extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
-         val &= 0x1f;
-       }
-      else if (op->extbits == 15)
-       {
-         extval = ((val >> 11) & 0xf) | (val & 0x7f0);
-         val &= 0xf;
-       }
-      else
-       {
-         extval = ((val & 0x1f) << 6) | (val & 0x20);
-         val = 0;
+         if (op->extu)
+           {
+             minext = 0;
+             maxext = (1 << op->extbits) - 1;
+           }
+         else
+           {
+             minext = - (1 << (op->extbits - 1));
+             maxext = (1 << (op->extbits - 1)) - 1;
+           }
+         if (val < minext || val > maxext)
+           as_bad_where (file, line,
+                         _("operand value out of range for instruction"));
        }
 
-      *extend = (unsigned short) extval;
-      *insn |= val;
+      *insn |= mips16_immed_extend (val, op->extbits);
     }
 }
 \f
@@ -14041,7 +14674,6 @@ struct percent_op_match
 static const struct percent_op_match mips_percent_op[] =
 {
   {"%lo", BFD_RELOC_LO16},
-#ifdef OBJ_ELF
   {"%call_hi", BFD_RELOC_MIPS_CALL_HI16},
   {"%call_lo", BFD_RELOC_MIPS_CALL_LO16},
   {"%call16", BFD_RELOC_MIPS_CALL16},
@@ -14063,7 +14695,6 @@ static const struct percent_op_match mips_percent_op[] =
   {"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16},
   {"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16},
   {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
-#endif
   {"%hi", BFD_RELOC_HI16_S}
 };
 
@@ -14073,7 +14704,14 @@ static const struct percent_op_match mips16_percent_op[] =
   {"%gprel", BFD_RELOC_MIPS16_GPREL},
   {"%got", BFD_RELOC_MIPS16_GOT16},
   {"%call16", BFD_RELOC_MIPS16_CALL16},
-  {"%hi", BFD_RELOC_MIPS16_HI16_S}
+  {"%hi", BFD_RELOC_MIPS16_HI16_S},
+  {"%tlsgd", BFD_RELOC_MIPS16_TLS_GD},
+  {"%tlsldm", BFD_RELOC_MIPS16_TLS_LDM},
+  {"%dtprel_hi", BFD_RELOC_MIPS16_TLS_DTPREL_HI16},
+  {"%dtprel_lo", BFD_RELOC_MIPS16_TLS_DTPREL_LO16},
+  {"%tprel_hi", BFD_RELOC_MIPS16_TLS_TPREL_HI16},
+  {"%tprel_lo", BFD_RELOC_MIPS16_TLS_TPREL_LO16},
+  {"%gottprel", BFD_RELOC_MIPS16_TLS_GOTTPREL}
 };
 
 
@@ -14210,7 +14848,6 @@ md_number_to_chars (char *buf, valueT val, int n)
     number_to_chars_littleendian (buf, val, n);
 }
 \f
-#ifdef OBJ_ELF
 static int support_64bit_objects(void)
 {
   const char **list, **l;
@@ -14225,214 +14862,6 @@ static int support_64bit_objects(void)
   free (list);
   return yes;
 }
-#endif /* OBJ_ELF */
-
-const char *md_shortopts = "O::g::G:";
-
-enum options
-  {
-    OPTION_MARCH = OPTION_MD_BASE,
-    OPTION_MTUNE,
-    OPTION_MIPS1,
-    OPTION_MIPS2,
-    OPTION_MIPS3,
-    OPTION_MIPS4,
-    OPTION_MIPS5,
-    OPTION_MIPS32,
-    OPTION_MIPS64,
-    OPTION_MIPS32R2,
-    OPTION_MIPS64R2,
-    OPTION_MIPS16,
-    OPTION_NO_MIPS16,
-    OPTION_MIPS3D,
-    OPTION_NO_MIPS3D,
-    OPTION_MDMX,
-    OPTION_NO_MDMX,
-    OPTION_DSP,
-    OPTION_NO_DSP,
-    OPTION_MT,
-    OPTION_NO_MT,
-    OPTION_SMARTMIPS,
-    OPTION_NO_SMARTMIPS,
-    OPTION_DSPR2,
-    OPTION_NO_DSPR2,
-    OPTION_MICROMIPS,
-    OPTION_NO_MICROMIPS,
-    OPTION_MCU,
-    OPTION_NO_MCU,
-    OPTION_COMPAT_ARCH_BASE,
-    OPTION_M4650,
-    OPTION_NO_M4650,
-    OPTION_M4010,
-    OPTION_NO_M4010,
-    OPTION_M4100,
-    OPTION_NO_M4100,
-    OPTION_M3900,
-    OPTION_NO_M3900,
-    OPTION_M7000_HILO_FIX,
-    OPTION_MNO_7000_HILO_FIX, 
-    OPTION_FIX_24K,
-    OPTION_NO_FIX_24K,
-    OPTION_FIX_LOONGSON2F_JUMP,
-    OPTION_NO_FIX_LOONGSON2F_JUMP,
-    OPTION_FIX_LOONGSON2F_NOP,
-    OPTION_NO_FIX_LOONGSON2F_NOP,
-    OPTION_FIX_VR4120,
-    OPTION_NO_FIX_VR4120,
-    OPTION_FIX_VR4130,
-    OPTION_NO_FIX_VR4130,
-    OPTION_FIX_CN63XXP1,
-    OPTION_NO_FIX_CN63XXP1,
-    OPTION_TRAP,
-    OPTION_BREAK,
-    OPTION_EB,
-    OPTION_EL,
-    OPTION_FP32,
-    OPTION_GP32,
-    OPTION_CONSTRUCT_FLOATS,
-    OPTION_NO_CONSTRUCT_FLOATS,
-    OPTION_FP64,
-    OPTION_GP64,
-    OPTION_RELAX_BRANCH,
-    OPTION_NO_RELAX_BRANCH,
-    OPTION_MSHARED,
-    OPTION_MNO_SHARED,
-    OPTION_MSYM32,
-    OPTION_MNO_SYM32,
-    OPTION_SOFT_FLOAT,
-    OPTION_HARD_FLOAT,
-    OPTION_SINGLE_FLOAT,
-    OPTION_DOUBLE_FLOAT,
-    OPTION_32,
-#ifdef OBJ_ELF
-    OPTION_CALL_SHARED,
-    OPTION_CALL_NONPIC,
-    OPTION_NON_SHARED,
-    OPTION_XGOT,
-    OPTION_MABI,
-    OPTION_N32,
-    OPTION_64,
-    OPTION_MDEBUG,
-    OPTION_NO_MDEBUG,
-    OPTION_PDR,
-    OPTION_NO_PDR,
-    OPTION_MVXWORKS_PIC,
-#endif /* OBJ_ELF */
-    OPTION_END_OF_ENUM    
-  };
-  
-struct option md_longopts[] =
-{
-  /* Options which specify architecture.  */
-  {"march", required_argument, NULL, OPTION_MARCH},
-  {"mtune", required_argument, NULL, OPTION_MTUNE},
-  {"mips0", no_argument, NULL, OPTION_MIPS1},
-  {"mips1", no_argument, NULL, OPTION_MIPS1},
-  {"mips2", no_argument, NULL, OPTION_MIPS2},
-  {"mips3", no_argument, NULL, OPTION_MIPS3},
-  {"mips4", no_argument, NULL, OPTION_MIPS4},
-  {"mips5", no_argument, NULL, OPTION_MIPS5},
-  {"mips32", no_argument, NULL, OPTION_MIPS32},
-  {"mips64", no_argument, NULL, OPTION_MIPS64},
-  {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
-  {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
-
-  /* Options which specify Application Specific Extensions (ASEs).  */
-  {"mips16", no_argument, NULL, OPTION_MIPS16},
-  {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-  {"mips3d", no_argument, NULL, OPTION_MIPS3D},
-  {"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
-  {"mdmx", no_argument, NULL, OPTION_MDMX},
-  {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
-  {"mdsp", no_argument, NULL, OPTION_DSP},
-  {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
-  {"mmt", no_argument, NULL, OPTION_MT},
-  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
-  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
-  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
-  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
-  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
-  {"mmicromips", no_argument, NULL, OPTION_MICROMIPS},
-  {"mno-micromips", no_argument, NULL, OPTION_NO_MICROMIPS},
-  {"mmcu", no_argument, NULL, OPTION_MCU},
-  {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
-
-  /* Old-style architecture options.  Don't add more of these.  */
-  {"m4650", no_argument, NULL, OPTION_M4650},
-  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
-  {"m4010", no_argument, NULL, OPTION_M4010},
-  {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
-  {"m4100", no_argument, NULL, OPTION_M4100},
-  {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
-  {"m3900", no_argument, NULL, OPTION_M3900},
-  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
-
-  /* Options which enable bug fixes.  */
-  {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
-  {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-  {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
-  {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
-  {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
-  {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
-  {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
-  {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
-  {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
-  {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
-  {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
-  {"mfix-24k",    no_argument, NULL, OPTION_FIX_24K},
-  {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
-  {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
-  {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
-
-  /* Miscellaneous options.  */
-  {"trap", no_argument, NULL, OPTION_TRAP},
-  {"no-break", no_argument, NULL, OPTION_TRAP},
-  {"break", no_argument, NULL, OPTION_BREAK},
-  {"no-trap", no_argument, NULL, OPTION_BREAK},
-  {"EB", no_argument, NULL, OPTION_EB},
-  {"EL", no_argument, NULL, OPTION_EL},
-  {"mfp32", no_argument, NULL, OPTION_FP32},
-  {"mgp32", no_argument, NULL, OPTION_GP32},
-  {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
-  {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
-  {"mfp64", no_argument, NULL, OPTION_FP64},
-  {"mgp64", no_argument, NULL, OPTION_GP64},
-  {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
-  {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
-  {"mshared", no_argument, NULL, OPTION_MSHARED},
-  {"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
-  {"msym32", no_argument, NULL, OPTION_MSYM32},
-  {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
-  {"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
-  {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
-  {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
-  {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
-
-  /* Strictly speaking this next option is ELF specific,
-     but we allow it for other ports as well in order to
-     make testing easier.  */
-  {"32",          no_argument, NULL, OPTION_32},
-  
-  /* ELF-specific options.  */
-#ifdef OBJ_ELF
-  {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
-  {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
-  {"call_nonpic", no_argument, NULL, OPTION_CALL_NONPIC},
-  {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
-  {"xgot",        no_argument, NULL, OPTION_XGOT},
-  {"mabi", required_argument, NULL, OPTION_MABI},
-  {"n32",         no_argument, NULL, OPTION_N32},
-  {"64",          no_argument, NULL, OPTION_64},
-  {"mdebug", no_argument, NULL, OPTION_MDEBUG},
-  {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
-  {"mpdr", no_argument, NULL, OPTION_PDR},
-  {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
-  {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
-#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:
@@ -14454,6 +14883,16 @@ mips_set_option_string (const char **string_ptr, const char *new_value)
 int
 md_parse_option (int c, char *arg)
 {
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
+    if (c == mips_ases[i].option_on || c == mips_ases[i].option_off)
+      {
+       file_ase_explicit |= mips_set_ase (&mips_ases[i],
+                                          c == mips_ases[i].option_on);
+       return 1;
+      }
+
   switch (c)
     {
     case OPTION_CONSTRUCT_FLOATS:
@@ -14574,50 +15013,6 @@ md_parse_option (int c, char *arg)
     case OPTION_NO_M3900:
       break;
 
-    case OPTION_MDMX:
-      mips_opts.ase_mdmx = 1;
-      break;
-
-    case OPTION_NO_MDMX:
-      mips_opts.ase_mdmx = 0;
-      break;
-
-    case OPTION_DSP:
-      mips_opts.ase_dsp = 1;
-      mips_opts.ase_dspr2 = 0;
-      break;
-
-    case OPTION_NO_DSP:
-      mips_opts.ase_dsp = 0;
-      mips_opts.ase_dspr2 = 0;
-      break;
-
-    case OPTION_DSPR2:
-      mips_opts.ase_dspr2 = 1;
-      mips_opts.ase_dsp = 1;
-      break;
-
-    case OPTION_NO_DSPR2:
-      mips_opts.ase_dspr2 = 0;
-      mips_opts.ase_dsp = 0;
-      break;
-
-    case OPTION_MT:
-      mips_opts.ase_mt = 1;
-      break;
-
-    case OPTION_NO_MT:
-      mips_opts.ase_mt = 0;
-      break;
-
-    case OPTION_MCU:
-      mips_opts.ase_mcu = 1;
-      break;
-
-    case OPTION_NO_MCU:
-      mips_opts.ase_mcu = 0;
-      break;
-
     case OPTION_MICROMIPS:
       if (mips_opts.mips16 == 1)
        {
@@ -14648,22 +15043,6 @@ md_parse_option (int c, char *arg)
       mips_no_prev_insn ();
       break;
 
-    case OPTION_MIPS3D:
-      mips_opts.ase_mips3d = 1;
-      break;
-
-    case OPTION_NO_MIPS3D:
-      mips_opts.ase_mips3d = 0;
-      break;
-
-    case OPTION_SMARTMIPS:
-      mips_opts.ase_smartmips = 1;
-      break;
-
-    case OPTION_NO_SMARTMIPS:
-      mips_opts.ase_smartmips = 0;
-      break;
-
     case OPTION_FIX_24K:
       mips_fix_24k = 1;
       break;
@@ -14720,6 +15099,14 @@ md_parse_option (int c, char *arg)
       mips_relax_branch = 0;
       break;
 
+    case OPTION_INSN32:
+      mips_opts.insn32 = TRUE;
+      break;
+
+    case OPTION_NO_INSN32:
+      mips_opts.insn32 = FALSE;
+      break;
+
     case OPTION_MSHARED:
       mips_in_shared = TRUE;
       break;
@@ -14736,36 +15123,20 @@ md_parse_option (int c, char *arg)
       mips_opts.sym32 = FALSE;
       break;
 
-#ifdef OBJ_ELF
       /* When generating ELF code, we permit -KPIC and -call_shared to
         select SVR4_PIC, and -non_shared to select no PIC.  This is
         intended to be compatible with Irix 5.  */
     case OPTION_CALL_SHARED:
-      if (!IS_ELF)
-       {
-         as_bad (_("-call_shared is supported only for ELF format"));
-         return 0;
-       }
       mips_pic = SVR4_PIC;
       mips_abicalls = TRUE;
       break;
 
     case OPTION_CALL_NONPIC:
-      if (!IS_ELF)
-       {
-         as_bad (_("-call_nonpic is supported only for ELF format"));
-         return 0;
-       }
       mips_pic = NO_PIC;
       mips_abicalls = TRUE;
       break;
 
     case OPTION_NON_SHARED:
-      if (!IS_ELF)
-       {
-         as_bad (_("-non_shared is supported only for ELF format"));
-         return 0;
-       }
       mips_pic = NO_PIC;
       mips_abicalls = FALSE;
       break;
@@ -14776,7 +15147,6 @@ md_parse_option (int c, char *arg)
     case OPTION_XGOT:
       mips_big_got = 1;
       break;
-#endif /* OBJ_ELF */
 
     case 'G':
       g_switch_value = atoi (arg);
@@ -14786,33 +15156,18 @@ md_parse_option (int c, char *arg)
       /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
         and -mabi=64.  */
     case OPTION_32:
-      if (IS_ELF)
-       mips_abi = O32_ABI;
-      /* We silently ignore -32 for non-ELF targets.  This greatly
-        simplifies the construction of the MIPS GAS test cases.  */
+      mips_abi = O32_ABI;
       break;
 
-#ifdef OBJ_ELF
     case OPTION_N32:
-      if (!IS_ELF)
-       {
-         as_bad (_("-n32 is supported for ELF format only"));
-         return 0;
-       }
       mips_abi = N32_ABI;
       break;
 
     case OPTION_64:
-      if (!IS_ELF)
-       {
-         as_bad (_("-64 is supported for ELF format only"));
-         return 0;
-       }
       mips_abi = N64_ABI;
       if (!support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
-#endif /* OBJ_ELF */
 
     case OPTION_GP32:
       file_mips_gp32 = 1;
@@ -14846,13 +15201,7 @@ md_parse_option (int c, char *arg)
       file_mips_soft_float = 0;
       break;
 
-#ifdef OBJ_ELF
     case OPTION_MABI:
-      if (!IS_ELF)
-       {
-         as_bad (_("-mabi is supported for ELF format only"));
-         return 0;
-       }
       if (strcmp (arg, "32") == 0)
        mips_abi = O32_ABI;
       else if (strcmp (arg, "o64") == 0)
@@ -14874,7 +15223,6 @@ md_parse_option (int c, char *arg)
          return 0;
        }
       break;
-#endif /* OBJ_ELF */
 
     case OPTION_M7000_HILO_FIX:
       mips_7000_hilo_fix = TRUE;
@@ -14884,7 +15232,6 @@ md_parse_option (int c, char *arg)
       mips_7000_hilo_fix = FALSE;
       break;
 
-#ifdef OBJ_ELF
     case OPTION_MDEBUG:
       mips_flag_mdebug = TRUE;
       break;
@@ -14904,7 +15251,18 @@ md_parse_option (int c, char *arg)
     case OPTION_MVXWORKS_PIC:
       mips_pic = VXWORKS_PIC;
       break;
-#endif /* OBJ_ELF */
+
+    case OPTION_NAN:
+      if (strcmp (arg, "2008") == 0)
+       mips_flag_nan2008 = TRUE;
+      else if (strcmp (arg, "legacy") == 0)
+       mips_flag_nan2008 = FALSE;
+      else
+       {
+         as_fatal (_("Invalid NaN setting -mnan=%s"), arg);
+         return 0;
+       }
+      break;
 
     default:
       return 0;
@@ -14985,7 +15343,10 @@ mips_after_parse_args (void)
     }
 
   if (arch_info == 0)
-    arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
+    {
+      arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
+      gas_assert (arch_info);
+    }
 
   if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
     as_bad (_("-march=%s is not compatible with the selected ABI"),
@@ -15036,7 +15397,7 @@ mips_after_parse_args (void)
       if (file_mips_gp32 == 0)
        /* 64-bit integer registers implies 64-bit float registers.  */
        file_mips_fp32 = 0;
-      else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0)
+      else if ((mips_opts.ase & FP64_ASES)
               && ISA_HAS_64BIT_FPRS (mips_opts.isa))
        /* -mips3d and -mdmx imply 64-bit float registers, if possible.  */
        file_mips_fp32 = 0;
@@ -15078,72 +15439,27 @@ mips_after_parse_args (void)
     mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
   if (mips_opts.micromips == -1)
     mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_arch)) ? 1 : 0;
-  if (mips_opts.ase_mips3d == -1)
-    mips_opts.ase_mips3d = ((arch_info->flags & MIPS_CPU_ASE_MIPS3D)
-                           && file_mips_fp32 == 0) ? 1 : 0;
-  if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
-    as_bad (_("-mfp32 used with -mips3d"));
-
-  if (mips_opts.ase_mdmx == -1)
-    mips_opts.ase_mdmx = ((arch_info->flags & MIPS_CPU_ASE_MDMX)
-                         && file_mips_fp32 == 0) ? 1 : 0;
-  if (mips_opts.ase_mdmx && file_mips_fp32 == 1)
-    as_bad (_("-mfp32 used with -mdmx"));
-
-  if (mips_opts.ase_smartmips == -1)
-    mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
-  if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
-    as_warn (_("%s ISA does not support SmartMIPS"), 
-            mips_cpu_info_from_isa (mips_opts.isa)->name);
-
-  if (mips_opts.ase_dsp == -1)
-    mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
-  if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
-    as_warn (_("%s ISA does not support DSP ASE"), 
-            mips_cpu_info_from_isa (mips_opts.isa)->name);
-
-  if (mips_opts.ase_dspr2 == -1)
-    {
-      mips_opts.ase_dspr2 = (arch_info->flags & MIPS_CPU_ASE_DSPR2) ? 1 : 0;
-      mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
-    }
-  if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
-    as_warn (_("%s ISA does not support DSP R2 ASE"),
-            mips_cpu_info_from_isa (mips_opts.isa)->name);
-
-  if (mips_opts.ase_mt == -1)
-    mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
-  if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
-    as_warn (_("%s ISA does not support MT ASE"),
-            mips_cpu_info_from_isa (mips_opts.isa)->name);
-
-  if (mips_opts.ase_mcu == -1)
-    mips_opts.ase_mcu = (arch_info->flags & MIPS_CPU_ASE_MCU) ? 1 : 0;
-  if (mips_opts.ase_mcu && !ISA_SUPPORTS_MCU_ASE)
-      as_warn (_("%s ISA does not support MCU ASE"),
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+
+  /* MIPS3D and MDMX require 64-bit FPRs, so -mfp32 should stop those
+     ASEs from being selected implicitly.  */
+  if (file_mips_fp32 == 1)
+    file_ase_explicit |= ASE_MIPS3D | ASE_MDMX;
+
+  /* If the user didn't explicitly select or deselect a particular ASE,
+     use the default setting for the CPU.  */
+  mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
 
   file_mips_isa = mips_opts.isa;
-  file_ase_mips3d = mips_opts.ase_mips3d;
-  file_ase_mdmx = mips_opts.ase_mdmx;
-  file_ase_smartmips = mips_opts.ase_smartmips;
-  file_ase_dsp = mips_opts.ase_dsp;
-  file_ase_dspr2 = mips_opts.ase_dspr2;
-  file_ase_mt = mips_opts.ase_mt;
+  file_ase = mips_opts.ase;
   mips_opts.gp32 = file_mips_gp32;
   mips_opts.fp32 = file_mips_fp32;
   mips_opts.soft_float = file_mips_soft_float;
   mips_opts.single_float = file_mips_single_float;
 
+  mips_check_isa_supports_ases ();
+
   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;
-    }
+    mips_flag_mdebug = 0;
 }
 \f
 void
@@ -15172,6 +15488,9 @@ md_pcrel_from (fixS *fixP)
       /* Return the address of the delay slot.  */
       return addr + 4;
 
+    case BFD_RELOC_32_PCREL:
+      return addr;
+
     default:
       /* We have no relocation type for PC relative MIPS16 instructions.  */
       if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
@@ -15262,9 +15581,11 @@ mips_frob_file (void)
       gas_assert (reloc_needs_lo_p (l->fixp->fx_r_type));
 
       /* If a GOT16 relocation turns out to be against a global symbol,
-        there isn't supposed to be a matching LO.  */
+        there isn't supposed to be a matching LO.  Ignore %gots against
+        constants; we'll report an error for those later.  */
       if (got16_reloc_p (l->fixp->fx_r_type)
-         && !pic_need_relax (l->fixp->fx_addsy, l->seg))
+         && !(l->fixp->fx_addsy
+              && pic_need_relax (l->fixp->fx_addsy, l->seg)))
        continue;
 
       /* Check quickly whether the next fixup happens to be a matching %lo.  */
@@ -15322,9 +15643,6 @@ mips_frob_file (void)
     }
 }
 
-/* We may have combined relocations without symbols in the N32/N64 ABI.
-   We have to prevent gas from dropping them.  */
-
 int
 mips_force_relocation (fixS *fixp)
 {
@@ -15338,23 +15656,40 @@ mips_force_relocation (fixS *fixp)
       || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
     return 1;
 
-  if (HAVE_NEWABI
-      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
-      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
-         || hi16_reloc_p (fixp->fx_r_type)
-         || lo16_reloc_p (fixp->fx_r_type)))
-    return 1;
-
   return 0;
 }
 
+/* Read the instruction associated with RELOC from BUF.  */
+
+static unsigned int
+read_reloc_insn (char *buf, bfd_reloc_code_real_type reloc)
+{
+  if (mips16_reloc_p (reloc) || micromips_reloc_p (reloc))
+    return read_compressed_insn (buf, 4);
+  else
+    return read_insn (buf);
+}
+
+/* Write instruction INSN to BUF, given that it has been relocated
+   by RELOC.  */
+
+static void
+write_reloc_insn (char *buf, bfd_reloc_code_real_type reloc,
+                 unsigned long insn)
+{
+  if (mips16_reloc_p (reloc) || micromips_reloc_p (reloc))
+    write_compressed_insn (buf, insn, 4);
+  else
+    write_insn (buf, insn);
+}
+
 /* Apply a fixup to the object file.  */
 
 void
 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
-  bfd_byte *buf;
-  long insn;
+  char *buf;
+  unsigned long insn;
   reloc_howto_type *howto;
 
   /* We ignore generic BFD relocations we don't know about.  */
@@ -15373,12 +15708,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
              || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
              || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
 
-  buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
+  buf = fixP->fx_frag->fr_literal + fixP->fx_where;
 
   gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
-             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
+             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
+             || fixP->fx_r_type == BFD_RELOC_32_PCREL);
 
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
@@ -15402,6 +15738,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
     case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
     case BFD_RELOC_MIPS_TLS_GOTTPREL:
+    case BFD_RELOC_MIPS_TLS_TPREL32:
+    case BFD_RELOC_MIPS_TLS_TPREL64:
     case BFD_RELOC_MIPS_TLS_TPREL_HI16:
     case BFD_RELOC_MIPS_TLS_TPREL_LO16:
     case BFD_RELOC_MICROMIPS_TLS_GD:
@@ -15411,6 +15749,19 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MICROMIPS_TLS_GOTTPREL:
     case BFD_RELOC_MICROMIPS_TLS_TPREL_HI16:
     case BFD_RELOC_MICROMIPS_TLS_TPREL_LO16:
+    case BFD_RELOC_MIPS16_TLS_GD:
+    case BFD_RELOC_MIPS16_TLS_LDM:
+    case BFD_RELOC_MIPS16_TLS_DTPREL_HI16:
+    case BFD_RELOC_MIPS16_TLS_DTPREL_LO16:
+    case BFD_RELOC_MIPS16_TLS_GOTTPREL:
+    case BFD_RELOC_MIPS16_TLS_TPREL_HI16:
+    case BFD_RELOC_MIPS16_TLS_TPREL_LO16:
+      if (!fixP->fx_addsy)
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("TLS relocation against a constant"));
+         break;
+       }
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* fall through */
 
@@ -15432,6 +15783,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_JALR:
     case BFD_RELOC_HI16:
     case BFD_RELOC_HI16_S:
+    case BFD_RELOC_LO16:
     case BFD_RELOC_GPREL16:
     case BFD_RELOC_MIPS_LITERAL:
     case BFD_RELOC_MIPS_CALL16:
@@ -15446,6 +15798,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS16_CALL16:
     case BFD_RELOC_MIPS16_HI16:
     case BFD_RELOC_MIPS16_HI16_S:
+    case BFD_RELOC_MIPS16_LO16:
     case BFD_RELOC_MIPS16_JMP:
     case BFD_RELOC_MICROMIPS_JMP:
     case BFD_RELOC_MICROMIPS_GOT_DISP:
@@ -15458,6 +15811,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MICROMIPS_JALR:
     case BFD_RELOC_MICROMIPS_HI16:
     case BFD_RELOC_MICROMIPS_HI16_S:
+    case BFD_RELOC_MICROMIPS_LO16:
     case BFD_RELOC_MICROMIPS_GPREL16:
     case BFD_RELOC_MICROMIPS_LITERAL:
     case BFD_RELOC_MICROMIPS_CALL16:
@@ -15466,7 +15820,24 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MICROMIPS_GOT_LO16:
     case BFD_RELOC_MICROMIPS_CALL_HI16:
     case BFD_RELOC_MICROMIPS_CALL_LO16:
-      /* Nothing needed to do.  The value comes from the reloc entry.  */
+    case BFD_RELOC_MIPS_EH:
+      if (fixP->fx_done)
+       {
+         offsetT value;
+
+         if (calculate_reloc (fixP->fx_r_type, *valP, &value))
+           {
+             insn = read_reloc_insn (buf, fixP->fx_r_type);
+             if (mips16_reloc_p (fixP->fx_r_type))
+               insn |= mips16_immed_extend (value, 16);
+             else
+               insn |= (value & 0xffff);
+             write_reloc_insn (buf, fixP->fx_r_type, insn);
+           }
+         else
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("Unsupported constant in relocation"));
+       }
       break;
 
     case BFD_RELOC_64:
@@ -15475,7 +15846,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       if (fixP->fx_done)
        {
          if (8 <= sizeof (valueT))
-           md_number_to_chars ((char *) buf, *valP, 8);
+           md_number_to_chars (buf, *valP, 8);
          else
            {
              valueT hiv;
@@ -15484,43 +15855,21 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
                hiv = 0xffffffff;
              else
                hiv = 0;
-             md_number_to_chars ((char *)(buf + (target_big_endian ? 4 : 0)),
-                                 *valP, 4);
-             md_number_to_chars ((char *)(buf + (target_big_endian ? 0 : 4)),
-                                 hiv, 4);
+             md_number_to_chars (buf + (target_big_endian ? 4 : 0), *valP, 4);
+             md_number_to_chars (buf + (target_big_endian ? 0 : 4), hiv, 4);
            }
        }
       break;
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
+    case BFD_RELOC_32_PCREL:
     case BFD_RELOC_16:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
         resolved when it appears but is later defined.  */
       if (fixP->fx_done)
-       md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
-      break;
-
-    case BFD_RELOC_LO16:
-    case BFD_RELOC_MIPS16_LO16:
-    case BFD_RELOC_MICROMIPS_LO16:
-      /* FIXME: Now that embedded-PIC is gone, some of this code/comment
-        may be safe to remove, but if so it's not obvious.  */
-      /* When handling an embedded PIC switch statement, we can wind
-        up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
-      if (fixP->fx_done)
-       {
-         if (*valP + 0x8000 > 0xffff)
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("relocation overflow"));
-         /* 32-bit microMIPS instructions are divided into two halfwords.
-            Relocations always refer to the second halfword, regardless
-            of endianness.  */
-         if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16)
-           buf += 2;
-         md_number_to_chars ((char *) buf, *valP, 2);
-       }
+       md_number_to_chars (buf, *valP, fixP->fx_size);
       break;
 
     case BFD_RELOC_16_PCREL_S2:
@@ -15535,15 +15884,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        break;
 
       /* Update old instruction data.  */
-      if (target_big_endian)
-       insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-      else
-       insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+      insn = read_insn (buf);
 
       if (*valP + 0x20000 <= 0x3ffff)
        {
          insn |= (*valP >> 2) & 0xffff;
-         md_number_to_chars ((char *) buf, insn, 4);
+         write_insn (buf, insn);
        }
       else if (mips_pic == NO_PIC
               && fixP->fx_done
@@ -15565,7 +15911,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          fixP->fx_done = 0;
          fixP->fx_addsy = section_symbol (text_section);
          *valP += md_pcrel_from (fixP);
-         md_number_to_chars ((char *) buf, insn, 4);
+         write_insn (buf, insn);
        }
       else
        {
@@ -15604,7 +15950,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     default:
-      internalError ();
+      abort ();
     }
 
   /* Remember value for tc_gen_reloc.  */
@@ -15629,11 +15975,18 @@ get_symbol (void)
    fill byte should be used, FILL points to an integer that contains
    that byte, otherwise FILL is null.
 
-   The MIPS assembler also automatically adjusts any preceding
-   label.  */
+   This function used to have the comment:
+
+      The MIPS assembler also automatically adjusts any preceding label.
+
+   The implementation therefore applied the adjustment to a maximum of
+   one label.  However, other label adjustments are applied to batches
+   of labels, and adjusting just one caused problems when new labels
+   were added for the sake of debugging or unwind information.
+   We therefore adjust all preceding labels (given as LABELS) instead.  */
 
 static void
-mips_align (int to, int *fill, symbolS *label)
+mips_align (int to, int *fill, struct insn_label_list *labels)
 {
   mips_emit_delays ();
   mips_record_compressed_mode ();
@@ -15642,12 +15995,7 @@ mips_align (int to, int *fill, symbolS *label)
   else
     frag_align (to, fill ? *fill : 0, 0);
   record_alignment (now_seg, to);
-  if (label != NULL)
-    {
-      gas_assert (S_GET_SEGMENT (label) == now_seg);
-      symbol_set_frag (label, frag_now);
-      S_SET_VALUE (label, (valueT) frag_now_fix ());
-    }
+  mips_move_labels (labels, FALSE);
 }
 
 /* Align to a given power of two.  .align 0 turns off the automatic
@@ -15689,7 +16037,7 @@ s_align (int x ATTRIBUTE_UNUSED)
       struct insn_label_list *l = si->label_list;
       /* Auto alignment should be switched on by next section change.  */
       auto_align = 1;
-      mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
+      mips_align (temp, fill_ptr, l);
     }
   else
     {
@@ -15704,16 +16052,13 @@ s_change_sec (int sec)
 {
   segT seg;
 
-#ifdef OBJ_ELF
   /* The ELF backend needs to know that we are changing sections, so
      that .previous works correctly.  We could do something like check
      for an obj_section_change_hook macro, but that might be confusing
      as it would not be appropriate to use it in the section changing
      functions in read.c, since obj-elf.c intercepts those.  FIXME:
      This should be cleaner, somehow.  */
-  if (IS_ELF)
-    obj_elf_section_change_hook ();
-#endif
+  obj_elf_section_change_hook ();
 
   mips_emit_delays ();
 
@@ -15733,37 +16078,28 @@ s_change_sec (int sec)
     case 'r':
       seg = subseg_new (RDATA_SECTION_NAME,
                        (subsegT) get_absolute_expression ());
-      if (IS_ELF)
-       {
-         bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
-                                                 | SEC_READONLY | SEC_RELOC
-                                                 | SEC_DATA));
-         if (strncmp (TARGET_OS, "elf", 3) != 0)
-           record_alignment (seg, 4);
-       }
+      bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
+                                             | SEC_READONLY | SEC_RELOC
+                                             | SEC_DATA));
+      if (strncmp (TARGET_OS, "elf", 3) != 0)
+       record_alignment (seg, 4);
       demand_empty_rest_of_line ();
       break;
 
     case 's':
       seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
-      if (IS_ELF)
-       {
-         bfd_set_section_flags (stdoutput, seg,
-                                SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
-         if (strncmp (TARGET_OS, "elf", 3) != 0)
-           record_alignment (seg, 4);
-       }
+      bfd_set_section_flags (stdoutput, seg,
+                            SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
+      if (strncmp (TARGET_OS, "elf", 3) != 0)
+       record_alignment (seg, 4);
       demand_empty_rest_of_line ();
       break;
 
     case 'B':
       seg = subseg_new (".sbss", (subsegT) get_absolute_expression ());
-      if (IS_ELF)
-       {
-         bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
-         if (strncmp (TARGET_OS, "elf", 3) != 0)
-           record_alignment (seg, 4);
-       }
+      bfd_set_section_flags (stdoutput, seg, SEC_ALLOC);
+      if (strncmp (TARGET_OS, "elf", 3) != 0)
+       record_alignment (seg, 4);
       demand_empty_rest_of_line ();
       break;
     }
@@ -15774,7 +16110,6 @@ s_change_sec (int sec)
 void
 s_change_section (int ignore ATTRIBUTE_UNUSED)
 {
-#ifdef OBJ_ELF
   char *section_name;
   char c;
   char next_c = 0;
@@ -15783,9 +16118,6 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   int section_entry_size;
   int section_alignment;
 
-  if (!IS_ELF)
-    return;
-
   section_name = input_line_pointer;
   c = get_symbol_end ();
   if (c)
@@ -15845,7 +16177,6 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
 
   if (now_seg->name != section_name)
     free (section_name);
-#endif /* OBJ_ELF */
 }
 
 void
@@ -15859,12 +16190,10 @@ s_cons (int log_size)
 {
   segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l = si->label_list;
-  symbolS *label;
 
-  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (log_size > 0 && auto_align)
-    mips_align (log_size, 0, label);
+    mips_align (log_size, 0, l);
   cons (1 << log_size);
   mips_clear_insn_labels ();
 }
@@ -15874,18 +16203,15 @@ s_float_cons (int type)
 {
   segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l = si->label_list;
-  symbolS *label;
-
-  label = l != NULL ? l->label : NULL;
 
   mips_emit_delays ();
 
   if (auto_align)
     {
       if (type == 'd')
-       mips_align (3, 0, label);
+       mips_align (3, 0, l);
       else
-       mips_align (2, 0, label);
+       mips_align (2, 0, l);
     }
 
   float_cons (type);
@@ -16012,6 +16338,7 @@ static void
 s_mipsset (int x ATTRIBUTE_UNUSED)
 {
   char *name = input_line_pointer, ch;
+  const struct mips_ase *ase;
 
   while (!is_end_of_line[(unsigned char) *input_line_pointer])
     ++input_line_pointer;
@@ -16117,62 +16444,12 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     }
   else if (strcmp (name, "nomicromips") == 0)
     mips_opts.micromips = 0;
-  else if (strcmp (name, "smartmips") == 0)
-    {
-      if (!ISA_SUPPORTS_SMARTMIPS)
-       as_warn (_("%s ISA does not support SmartMIPS ASE"), 
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.ase_smartmips = 1;
-    }
-  else if (strcmp (name, "nosmartmips") == 0)
-    mips_opts.ase_smartmips = 0;
-  else if (strcmp (name, "mips3d") == 0)
-    mips_opts.ase_mips3d = 1;
-  else if (strcmp (name, "nomips3d") == 0)
-    mips_opts.ase_mips3d = 0;
-  else if (strcmp (name, "mdmx") == 0)
-    mips_opts.ase_mdmx = 1;
-  else if (strcmp (name, "nomdmx") == 0)
-    mips_opts.ase_mdmx = 0;
-  else if (strcmp (name, "dsp") == 0)
-    {
-      if (!ISA_SUPPORTS_DSP_ASE)
-       as_warn (_("%s ISA does not support DSP ASE"), 
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.ase_dsp = 1;
-      mips_opts.ase_dspr2 = 0;
-    }
-  else if (strcmp (name, "nodsp") == 0)
-    {
-      mips_opts.ase_dsp = 0;
-      mips_opts.ase_dspr2 = 0;
-    }
-  else if (strcmp (name, "dspr2") == 0)
-    {
-      if (!ISA_SUPPORTS_DSPR2_ASE)
-       as_warn (_("%s ISA does not support DSP R2 ASE"),
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.ase_dspr2 = 1;
-      mips_opts.ase_dsp = 1;
-    }
-  else if (strcmp (name, "nodspr2") == 0)
-    {
-      mips_opts.ase_dspr2 = 0;
-      mips_opts.ase_dsp = 0;
-    }
-  else if (strcmp (name, "mt") == 0)
-    {
-      if (!ISA_SUPPORTS_MT_ASE)
-       as_warn (_("%s ISA does not support MT ASE"), 
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.ase_mt = 1;
-    }
-  else if (strcmp (name, "nomt") == 0)
-    mips_opts.ase_mt = 0;
-  else if (strcmp (name, "mcu") == 0)
-    mips_opts.ase_mcu = 1;
-  else if (strcmp (name, "nomcu") == 0)
-    mips_opts.ase_mcu = 0;
+  else if (name[0] == 'n'
+          && name[1] == 'o'
+          && (ase = mips_lookup_ase (name + 2)))
+    mips_set_ase (ase, FALSE);
+  else if ((ase = mips_lookup_ase (name)))
+    mips_set_ase (ase, TRUE);
   else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
     {
       int reset = 0;
@@ -16231,7 +16508,14 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        case ISA_MIPS64:
        case ISA_MIPS64R2:
          mips_opts.gp32 = 0;
+         if (mips_opts.arch == CPU_R5900)
+           {
+               mips_opts.fp32 = 1;
+           }
+         else
+           {
          mips_opts.fp32 = 0;
+           }
          break;
        default:
          as_bad (_("unknown ISA level %s"), name + 4);
@@ -16247,6 +16531,10 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.noautoextend = 0;
   else if (strcmp (name, "noautoextend") == 0)
     mips_opts.noautoextend = 1;
+  else if (strcmp (name, "insn32") == 0)
+    mips_opts.insn32 = TRUE;
+  else if (strcmp (name, "noinsn32") == 0)
+    mips_opts.insn32 = FALSE;
   else if (strcmp (name, "push") == 0)
     {
       struct mips_option_stack *s;
@@ -16293,6 +16581,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     {
       as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
     }
+  mips_check_isa_supports_ases ();
   *input_line_pointer = ch;
   demand_empty_rest_of_line ();
 }
@@ -16347,6 +16636,13 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (mips_opts.mips16)
+    {
+      as_bad (_("%s not supported in MIPS16 mode"), ".cpload");
+      ignore_rest_of_line ();
+      return;
+    }
+
   /* .cpload should be in a .set noreorder section.  */
   if (mips_opts.noreorder == 0)
     as_warn (_(".cpload not in noreorder section"));
@@ -16366,6 +16662,9 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
   symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   macro_build_lui (&ex, mips_gp_register);
   macro_build (&ex, "addiu", "t,r,j", mips_gp_register,
@@ -16375,6 +16674,7 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
                 mips_gp_register, reg);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16413,6 +16713,13 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (mips_opts.mips16)
+    {
+      as_bad (_("%s not supported in MIPS16 mode"), ".cpsetup");
+      ignore_rest_of_line ();
+      return;
+    }
+
   reg1 = tc_get_register (0);
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
@@ -16444,6 +16751,9 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   SKIP_WHITESPACE ();
   expression (&ex_sym);
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16491,6 +16801,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
 
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16505,6 +16816,13 @@ s_cplocal (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (mips_opts.mips16)
+    {
+      as_bad (_("%s not supported in MIPS16 mode"), ".cplocal");
+      ignore_rest_of_line ();
+      return;
+    }
+
   mips_gp_register = tc_get_register (0);
   demand_empty_rest_of_line ();
 }
@@ -16526,6 +16844,13 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (mips_opts.mips16)
+    {
+      as_bad (_("%s not supported in MIPS16 mode"), ".cprestore");
+      ignore_rest_of_line ();
+      return;
+    }
+
   mips_cprestore_offset = get_absolute_expression ();
   mips_cprestore_valid = 1;
 
@@ -16534,11 +16859,15 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
   ex.X_op_symbol = NULL;
   ex.X_add_number = mips_cprestore_offset;
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   macro_build_ldst_constoffset (&ex, ADDRESS_STORE_INSN, mips_gp_register,
                                SP, HAVE_64BIT_ADDRESSES);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16562,6 +16891,16 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  if (mips_opts.mips16)
+    {
+      as_bad (_("%s not supported in MIPS16 mode"), ".cpreturn");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16577,15 +16916,18 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
                 mips_cpreturn_register, 0);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
-/* Handle the .dtprelword and .dtpreldword pseudo-ops.  They generate
-   a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
-   use in DWARF debug information.  */
+/* Handle a .dtprelword, .dtpreldword, .tprelword, or .tpreldword
+   pseudo-op; DIRSTR says which. The pseudo-op generates a BYTES-size
+   DTP- or TP-relative relocation of type RTYPE, for use in either DWARF
+   debug information or MIPS16 TLS.  */
 
 static void
-s_dtprel_internal (size_t bytes)
+s_tls_rel_directive (const size_t bytes, const char *dirstr,
+                    bfd_reloc_code_real_type rtype)
 {
   expressionS ex;
   char *p;
@@ -16594,20 +16936,15 @@ s_dtprel_internal (size_t bytes)
 
   if (ex.X_op != O_symbol)
     {
-      as_bad (_("Unsupported use of %s"), (bytes == 8
-                                          ? ".dtpreldword"
-                                          : ".dtprelword"));
+      as_bad (_("Unsupported use of %s"), dirstr);
       ignore_rest_of_line ();
     }
 
   p = frag_more (bytes);
   md_number_to_chars (p, 0, bytes);
-  fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
-              (bytes == 8
-               ? BFD_RELOC_MIPS_TLS_DTPREL64
-               : BFD_RELOC_MIPS_TLS_DTPREL32));
-
+  fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE, rtype);
   demand_empty_rest_of_line ();
+  mips_clear_insn_labels ();
 }
 
 /* Handle .dtprelword.  */
@@ -16615,7 +16952,7 @@ s_dtprel_internal (size_t bytes)
 static void
 s_dtprelword (int ignore ATTRIBUTE_UNUSED)
 {
-  s_dtprel_internal (4);
+  s_tls_rel_directive (4, ".dtprelword", BFD_RELOC_MIPS_TLS_DTPREL32);
 }
 
 /* Handle .dtpreldword.  */
@@ -16623,7 +16960,23 @@ s_dtprelword (int ignore ATTRIBUTE_UNUSED)
 static void
 s_dtpreldword (int ignore ATTRIBUTE_UNUSED)
 {
-  s_dtprel_internal (8);
+  s_tls_rel_directive (8, ".dtpreldword", BFD_RELOC_MIPS_TLS_DTPREL64);
+}
+
+/* Handle .tprelword.  */
+
+static void
+s_tprelword (int ignore ATTRIBUTE_UNUSED)
+{
+  s_tls_rel_directive (4, ".tprelword", BFD_RELOC_MIPS_TLS_TPREL32);
+}
+
+/* Handle .tpreldword.  */
+
+static void
+s_tpreldword (int ignore ATTRIBUTE_UNUSED)
+{
+  s_tls_rel_directive (8, ".tpreldword", BFD_RELOC_MIPS_TLS_TPREL64);
 }
 
 /* Handle the .gpvalue pseudo-op.  This is used when generating NewABI PIC
@@ -16653,7 +17006,6 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
 {
   segment_info_type *si;
   struct insn_label_list *l;
-  symbolS *label;
   expressionS ex;
   char *p;
 
@@ -16666,10 +17018,9 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
 
   si = seg_info (now_seg);
   l = si->label_list;
-  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
-    mips_align (2, 0, label);
+    mips_align (2, 0, l);
 
   expression (&ex);
   mips_clear_insn_labels ();
@@ -16693,7 +17044,6 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
 {
   segment_info_type *si;
   struct insn_label_list *l;
-  symbolS *label;
   expressionS ex;
   char *p;
 
@@ -16706,10 +17056,9 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
 
   si = seg_info (now_seg);
   l = si->label_list;
-  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
-    mips_align (3, 0, label);
+    mips_align (3, 0, l);
 
   expression (&ex);
   mips_clear_insn_labels ();
@@ -16732,6 +17081,34 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .ehword pseudo-op.  This is used when generating unwinding
+   tables.  It generates a R_MIPS_EH reloc.  */
+
+static void
+s_ehword (int ignore ATTRIBUTE_UNUSED)
+{
+  expressionS ex;
+  char *p;
+
+  mips_emit_delays ();
+
+  expression (&ex);
+  mips_clear_insn_labels ();
+
+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
+    {
+      as_bad (_("Unsupported use of .ehword"));
+      ignore_rest_of_line ();
+    }
+
+  p = frag_more (4);
+  md_number_to_chars (p, 0, 4);
+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
+              BFD_RELOC_MIPS_EH);
+
+  demand_empty_rest_of_line ();
+}
+
 /* Handle the .cpadd pseudo-op.  This is used when dealing with switch
    tables in SVR4 PIC code.  */
 
@@ -16747,12 +17124,16 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   /* Add $gp to the register named as an argument.  */
   macro_start ();
   reg = tc_get_register (0);
   macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16773,18 +17154,48 @@ s_insn (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Handle a .stabn directive.  We need these in order to mark a label
-   as being a mips16 text label correctly.  Sometimes the compiler
-   will emit a label, followed by a .stabn, and then switch sections.
-   If the label and .stabn are in mips16 mode, then the label is
-   really a mips16 text label.  */
+/* Handle the .nan pseudo-op.  */
 
 static void
-s_mips_stab (int type)
+s_nan (int ignore ATTRIBUTE_UNUSED)
 {
-  if (type == 'n')
-    mips_mark_labels ();
+  static const char str_legacy[] = "legacy";
+  static const char str_2008[] = "2008";
+  size_t i;
+
+  for (i = 0; !is_end_of_line[(unsigned char) input_line_pointer[i]]; i++);
+
+  if (i == sizeof (str_2008) - 1
+      && memcmp (input_line_pointer, str_2008, i) == 0)
+    mips_flag_nan2008 = TRUE;
+  else if (i == sizeof (str_legacy) - 1
+          && memcmp (input_line_pointer, str_legacy, i) == 0)
+    mips_flag_nan2008 = FALSE;
+  else
+    as_bad (_("Bad .nan directive"));
 
+  input_line_pointer += i;
+  demand_empty_rest_of_line ();
+}
+
+/* Handle a .stab[snd] directive.  Ideally these directives would be
+   implemented in a transparent way, so that removing them would not
+   have any effect on the generated instructions.  However, s_stab
+   internally changes the section, so in practice we need to decide
+   now whether the preceding label marks compressed code.  We do not
+   support changing the compression mode of a label after a .stab*
+   directive, such as in:
+
+   foo:
+       .stabs ...
+       .set mips16
+
+   so the current mode wins.  */
+
+static void
+s_mips_stab (int type)
+{
+  mips_mark_labels ();
   s_stab (type);
 }
 
@@ -16861,17 +17272,14 @@ md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
 
-  if (IS_ELF)
-    {
-      /* We don't need to align ELF sections to the full alignment.
-        However, Irix 5 may prefer that we align them at least to a 16
-        byte boundary.  We don't bother to align the sections if we
-        are targeted for an embedded system.  */
-      if (strncmp (TARGET_OS, "elf", 3) == 0)
-        return addr;
-      if (align > 4)
-        align = 4;
-    }
+  /* We don't need to align ELF sections to the full alignment.
+     However, Irix 5 may prefer that we align them at least to a 16
+     byte boundary.  We don't bother to align the sections if we
+     are targeted for an embedded system.  */
+  if (strncmp (TARGET_OS, "elf", 3) == 0)
+    return addr;
+  if (align > 4)
+    align = 4;
 
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
@@ -16974,15 +17382,12 @@ pic_need_relax (symbolS *sym, asection *segtype)
   symsec = S_GET_SEGMENT (sym);
 
   /* This must duplicate the test in adjust_reloc_syms.  */
-  return (symsec != &bfd_und_section
-         && symsec != &bfd_abs_section
+  return (!bfd_is_und_section (symsec)
+         && !bfd_is_abs_section (symsec)
          && !bfd_is_com_section (symsec)
          && !s_is_linkonce (sym, segtype)
-#ifdef OBJ_ELF
          /* A global or weak symbol is treated as external.  */
-         && (!IS_ELF || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
-#endif
-         );
+         && (!S_IS_WEAK (sym) && !S_IS_EXTERNAL (sym)));
 }
 
 
@@ -17491,14 +17896,14 @@ mips_fix_adjustable (fixS *fixp)
     return 0;
 
   /* There is no place to store an in-place offset for JALR relocations.
-     Likewise an in-range offset of PC-relative relocations may overflow
-     the in-place relocatable field if recalculated against the start
-     address of the symbol's containing section.  */
+     Likewise an in-range offset of limited PC-relative relocations may
+     overflow the in-place relocatable field if recalculated against the
+     start address of the symbol's containing section.  */
   if (HAVE_IN_PLACE_ADDENDS
-      && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type)))
+      && (limited_pcrel_reloc_p (fixp->fx_r_type)
+         || jalr_reloc_p (fixp->fx_r_type)))
     return 0;
 
-#ifdef OBJ_ELF
   /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
      to a floating-point stub.  The same is true for non-R_MIPS16_26
      relocations against MIPS16 functions; in this case, the stub becomes
@@ -17541,15 +17946,13 @@ mips_fix_adjustable (fixS *fixp)
      targets.)  This approach is a little simpler than trying to detect
      stub sections, and gives the "all or nothing" per-symbol consistency
      that we have for MIPS16 symbols.  */
-  if (IS_ELF
-      && fixp->fx_subsy == NULL
+  if (fixp->fx_subsy == NULL
       && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
          || *symbol_get_tc (fixp->fx_addsy)
          || (HAVE_IN_PLACE_ADDENDS
              && ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
              && jmp_reloc_p (fixp->fx_r_type))))
     return 0;
-#endif
 
   return 1;
 }
@@ -17575,19 +17978,12 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
-                 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
+                 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
+                 || fixp->fx_r_type == BFD_RELOC_32_PCREL);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
       reloc->addend = fixp->fx_addnumber + reloc->address;
-      if (!IS_ELF)
-       {
-         /* A gruesome hack which is a result of the gruesome gas
-            reloc handling.  What's worse, for COFF (as opposed to
-            ECOFF), we might need yet another copy of reloc->address.
-            See bfd_install_relocation.  */
-         reloc->addend += reloc->address;
-       }
     }
   else
     reloc->addend = fixp->fx_addnumber;
@@ -17671,17 +18067,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
 {
   if (RELAX_BRANCH_P (fragp->fr_subtype))
     {
-      bfd_byte *buf;
+      char *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);
+      buf = fragp->fr_literal + fragp->fr_fix;
+      insn = read_insn (buf);
 
       if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
        {
@@ -17692,13 +18084,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          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, TRUE, BFD_RELOC_16_PCREL_S2);
+         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
+                             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;
+         buf = write_insn (buf, insn);
        }
       else
        {
@@ -17716,10 +18107,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              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???????.  */
-                 gas_assert ((insn & 0xf1000000) == 0x41000000);
+                 /* bc[0-3][tf]l? instructions can have the condition
+                    reversed by tweaking a single TF bit, and their
+                    opcodes all have 0x4???????.  */
+                 gas_assert ((insn & 0xf3e00000) == 0x41000000);
                  insn ^= 0x00010000;
                  break;
 
@@ -17759,7 +18150,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          else
            {
              /* How many bytes in instructions we've already emitted?  */
-             i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
+             i = buf - fragp->fr_literal - fragp->fr_fix;
              /* How many bytes in instructions from here to the end?  */
              i = fragp->fr_var - i;
            }
@@ -17769,12 +18160,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          i--;
          insn |= i;
          /* Branch over the jump.  */
-         md_number_to_chars ((char *) buf, insn, 4);
-         buf += 4;
+         buf = write_insn (buf, insn);
 
          /* nop */
-         md_number_to_chars ((char *) buf, 0, 4);
-         buf += 4;
+         buf = write_insn (buf, 0);
 
          if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
            {
@@ -17783,20 +18172,17 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              /* 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;
+             i = buf - 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;
+             buf = write_insn (buf, insn);
+             buf = write_insn (buf, 0);
            }
 
        uncond:
@@ -17809,13 +18195,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              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, FALSE, BFD_RELOC_MIPS_JMP);
+             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+                                 FALSE, 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;
+             buf = write_insn (buf, insn);
            }
          else
            {
@@ -17834,32 +18219,27 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                  exp.X_add_number = 0;
                }
 
-             fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, FALSE, BFD_RELOC_MIPS_GOT16);
+             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+                                 FALSE, 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;
+             buf = write_insn (buf, insn);
 
              if (mips_opts.isa == ISA_MIPS1)
-               {
-                 /* nop */
-                 md_number_to_chars ((char *) buf, 0, 4);
-                 buf += 4;
-               }
+               /* nop */
+               buf = write_insn (buf, 0);
 
              /* d/addiu $at, $at, <sym>  R_MIPS_LO16 */
              insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
              insn |= at << OP_SH_RS | at << OP_SH_RT;
 
-             fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, FALSE, BFD_RELOC_LO16);
+             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
+                                 FALSE, 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;
+             buf = write_insn (buf, insn);
 
              /* j(al)r $at.  */
              if (RELAX_BRANCH_LINK (fragp->fr_subtype))
@@ -17868,23 +18248,19 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                insn = 0x00000008;
              insn |= at << OP_SH_RS;
 
-             md_number_to_chars ((char *) buf, insn, 4);
-             buf += 4;
+             buf = write_insn (buf, insn);
            }
        }
 
-      gas_assert (buf == (bfd_byte *)fragp->fr_literal
-             + fragp->fr_fix + fragp->fr_var);
-
       fragp->fr_fix += fragp->fr_var;
-
+      gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
       return;
     }
 
   /* Relax microMIPS branches.  */
   if (RELAX_MICROMIPS_P (fragp->fr_subtype))
     {
-      bfd_byte *buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
+      char *buf = fragp->fr_literal + fragp->fr_fix;
       bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
       bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
       int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
@@ -17906,14 +18282,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
             because if there is linker relaxation, we're going to
             need the relocations.  */
          if (type == 'D')
-           fixp = fix_new_exp (fragp,
-                               buf - (bfd_byte *) fragp->fr_literal,
-                               2, &exp, TRUE,
+           fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
                                BFD_RELOC_MICROMIPS_10_PCREL_S1);
          else if (type == 'E')
-           fixp = fix_new_exp (fragp,
-                               buf - (bfd_byte *) fragp->fr_literal,
-                               2, &exp, TRUE,
+           fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
                                BFD_RELOC_MICROMIPS_7_PCREL_S1);
          else
            abort ();
@@ -17935,8 +18307,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* We generate a fixup instead of applying it right now,
             because if there is linker relaxation, we're going to
             need the relocations.  */
-         fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                             4, &exp, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
+         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
+                             BFD_RELOC_MICROMIPS_16_PCREL_S1);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -17947,10 +18319,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       /* Relax 16-bit branches to 32-bit branches.  */
       if (type != 0)
        {
-         if (target_big_endian)
-           insn = bfd_getb16 (buf);
-         else
-           insn = bfd_getl16 (buf);
+         insn = read_compressed_insn (buf, 2);
 
          if ((insn & 0xfc00) == 0xcc00)                /* b16  */
            insn = 0x94000000;                          /* beq  */
@@ -17970,32 +18339,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
              || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
            {
-             md_number_to_chars ((char *) buf, insn >> 16, 2);
-             buf += 2;
-             md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-             buf += 2;
-
-             gas_assert (buf == ((bfd_byte *) fragp->fr_literal
-                                 + fragp->fr_fix));
+             buf = write_compressed_insn (buf, insn, 4);
+             gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
              return;
            }
        }
       else
-       {
-         unsigned long next;
-
-         if (target_big_endian)
-           {
-             insn = bfd_getb16 (buf);
-             next = bfd_getb16 (buf + 2);
-           }
-         else
-           {
-             insn = bfd_getl16 (buf);
-             next = bfd_getl16 (buf + 2);
-           }
-         insn = (insn << 16) | next;
-       }
+       insn = read_compressed_insn (buf, 4);
 
       /* Relax 32-bit branches to a sequence of instructions.  */
       as_warn_where (fragp->fr_file, fragp->fr_line,
@@ -18044,30 +18394,19 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* Make a label at the end for use with the branch.  */
          l = symbol_new (micromips_label_name (), asec, fragp->fr_fix, fragp);
          micromips_label_inc ();
-#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
-         if (IS_ELF)
-           S_SET_OTHER (l, ELF_ST_SET_MICROMIPS (S_GET_OTHER (l)));
-#endif
+         S_SET_OTHER (l, ELF_ST_SET_MICROMIPS (S_GET_OTHER (l)));
 
          /* Refer to it.  */
-         fixp = fix_new (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                         4, l, 0, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4, l, 0, TRUE,
+                         BFD_RELOC_MICROMIPS_16_PCREL_S1);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
          /* Branch over the jump.  */
-         md_number_to_chars ((char *) buf, insn >> 16, 2);
-         buf += 2;
-         md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-         buf += 2;
-
+         buf = write_compressed_insn (buf, insn, 4);
          if (!compact)
-           {
-             /* nop  */
-             insn = 0x0c00;
-             md_number_to_chars ((char *) buf, insn, 2);
-             buf += 2;
-           }
+           /* nop */
+           buf = write_compressed_insn (buf, 0x0c00, 2);
        }
 
       if (mips_pic == NO_PIC)
@@ -18077,23 +18416,15 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* j/jal/jals <sym>  R_MICROMIPS_26_S1  */
          insn = al ? jal : 0xd4000000;
 
-         fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                             4, &exp, FALSE, BFD_RELOC_MICROMIPS_JMP);
+         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+                             BFD_RELOC_MICROMIPS_JMP);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
-         md_number_to_chars ((char *) buf, insn >> 16, 2);
-         buf += 2;
-         md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-         buf += 2;
-
+         buf = write_compressed_insn (buf, insn, 4);
          if (compact)
-           {
-             /* nop  */
-             insn = 0x0c00;
-             md_number_to_chars ((char *) buf, insn, 2);
-             buf += 2;
-           }
+           /* nop */
+           buf = write_compressed_insn (buf, 0x0c00, 2);
        }
       else
        {
@@ -18111,39 +18442,32 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              exp.X_add_number = 0;
            }
 
-         fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                             4, &exp, FALSE, BFD_RELOC_MICROMIPS_GOT16);
+         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+                             BFD_RELOC_MICROMIPS_GOT16);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
-         md_number_to_chars ((char *) buf, insn >> 16, 2);
-         buf += 2;
-         md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-         buf += 2;
+         buf = write_compressed_insn (buf, insn, 4);
 
          /* d/addiu $at, $at, <sym>  R_MICROMIPS_LO16  */
          insn = HAVE_64BIT_ADDRESSES ? 0x5c000000 : 0x30000000;
          insn |= at << MICROMIPSOP_SH_RT | at << MICROMIPSOP_SH_RS;
 
-         fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                             4, &exp, FALSE, BFD_RELOC_MICROMIPS_LO16);
+         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
+                             BFD_RELOC_MICROMIPS_LO16);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
-         md_number_to_chars ((char *) buf, insn >> 16, 2);
-         buf += 2;
-         md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-         buf += 2;
+         buf = write_compressed_insn (buf, insn, 4);
 
          /* jr/jrc/jalr/jalrs $at  */
          insn = al ? jalr : jr;
          insn |= at << MICROMIPSOP_SH_MJ;
 
-         md_number_to_chars ((char *) buf, insn & 0xffff, 2);
-         buf += 2;
+         buf = write_compressed_insn (buf, insn, 2);
        }
 
-      gas_assert (buf == (bfd_byte *) fragp->fr_literal + fragp->fr_fix);
+      gas_assert (buf == fragp->fr_literal + fragp->fr_fix);
       return;
     }
 
@@ -18151,29 +18475,18 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
     {
       int type;
       const struct mips16_immed_operand *op;
-      bfd_boolean small, ext;
       offsetT val;
-      bfd_byte *buf;
+      char *buf;
+      unsigned int user_length, length;
       unsigned long insn;
-      bfd_boolean use_extend;
-      unsigned short extend;
+      bfd_boolean ext;
 
       type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
       op = mips16_immed_operands;
       while (op->type != type)
        ++op;
 
-      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
-       {
-         small = FALSE;
-         ext = TRUE;
-       }
-      else
-       {
-         small = TRUE;
-         ext = FALSE;
-       }
-
+      ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype);
       val = resolve_symbol_value (fragp->fr_symbol);
       if (op->pcrel)
        {
@@ -18213,27 +18526,26 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
        as_warn_where (fragp->fr_file, fragp->fr_line,
                       _("extended instruction in delay slot"));
 
-      buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
+      buf = fragp->fr_literal + fragp->fr_fix;
 
-      if (target_big_endian)
-       insn = bfd_getb16 (buf);
-      else
-       insn = bfd_getl16 (buf);
+      insn = read_compressed_insn (buf, 2);
+      if (ext)
+       insn |= MIPS16_EXTEND;
 
-      mips16_immed (fragp->fr_file, fragp->fr_line, type, val,
-                   RELAX_MIPS16_USER_EXT (fragp->fr_subtype),
-                   small, ext, &insn, &use_extend, &extend);
+      if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
+       user_length = 4;
+      else if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
+       user_length = 2;
+      else
+       user_length = 0;
 
-      if (use_extend)
-       {
-         md_number_to_chars ((char *) buf, 0xf000 | extend, 2);
-         fragp->fr_fix += 2;
-         buf += 2;
-       }
+      mips16_immed (fragp->fr_file, fragp->fr_line, type,
+                   BFD_RELOC_UNUSED, val, user_length, &insn);
 
-      md_number_to_chars ((char *) buf, insn, 2);
-      fragp->fr_fix += 2;
-      buf += 2;
+      length = (ext ? 4 : 2);
+      gas_assert (mips16_opcode_length (insn) == length);
+      write_compressed_insn (buf, insn, length);
+      fragp->fr_fix += length;
     }
   else
     {
@@ -18316,8 +18628,6 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
     }
 }
 
-#ifdef OBJ_ELF
-
 /* This function is called after the relocs have been generated.
    We've been storing mips16 text labels as odd.  Here we convert them
    back to even for the convenience of the debugger.  */
@@ -18328,9 +18638,6 @@ mips_frob_file_after_relocs (void)
   asymbol **syms;
   unsigned int count, i;
 
-  if (!IS_ELF)
-    return;
-
   syms = bfd_get_outsymbols (stdoutput);
   count = bfd_get_symcount (stdoutput);
   for (i = 0; i < count; i++, syms++)
@@ -18345,15 +18652,13 @@ mips_frob_file_after_relocs (void)
       }
 }
 
-#endif
-
 /* This function is called whenever a label is defined, including fake
    labels instantiated off the dot special symbol.  It is used when
    handling branch delays; if a branch has a label, we assume we cannot
    move it.  This also bumps the value of the symbol by 1 in compressed
    code.  */
 
-void
+static void
 mips_record_label (symbolS *sym)
 {
   segment_info_type *si = seg_info (now_seg);
@@ -18379,13 +18684,20 @@ void
 mips_define_label (symbolS *sym)
 {
   mips_record_label (sym);
-#ifdef OBJ_ELF
   dwarf2_emit_label (sym);
-#endif
 }
-\f
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 
+/* This function is called by tc_new_dot_label whenever a new dot symbol
+   is defined.  */
+
+void
+mips_add_dot_label (symbolS *sym)
+{
+  mips_record_label (sym);
+  if (mips_assembling_insn && HAVE_CODE_COMPRESSION)
+    mips_compressed_mark_label (sym);
+}
+\f
 /* Some special processing for a MIPS ELF file.  */
 
 void
@@ -18436,21 +18748,13 @@ mips_elf_final_processing (void)
   if (mips_abicalls)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
 
-  /* Set MIPS ELF flags for ASEs.  */
-  /* We may need to define a new flag for DSP ASE, and set this flag when
-     file_ase_dsp is true.  */
-  /* Same for DSP R2.  */
-  /* We may need to define a new flag for MT ASE, and set this flag when
-     file_ase_mt is true.  */
+  /* Set MIPS ELF flags for ASEs.  Note that not all ASEs have flags
+     defined at present; this might need to change in future.  */
   if (file_ase_mips16)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
   if (file_ase_micromips)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
-#if 0 /* XXX FIXME */
-  if (file_ase_mips3d)
-    elf_elfheader (stdoutput)->e_flags |= ???;
-#endif
-  if (file_ase_mdmx)
+  if (file_ase & ASE_MDMX)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
 
   /* Set the MIPS ELF ABI flags.  */
@@ -18473,14 +18777,15 @@ mips_elf_final_processing (void)
   if (mips_32bitmode)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
 
+  if (mips_flag_nan2008)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
+
 #if 0 /* XXX FIXME */
   /* 32 bit code with 64 bit FP registers.  */
   if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
     elf_elfheader (stdoutput)->e_flags |= ???;
 #endif
 }
-
-#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
 \f
 typedef struct proc {
   symbolS *func_sym;
@@ -18564,10 +18869,9 @@ mips_handle_align (fragS *fragp)
       *p++ = '\0';
       /* Fall through.  */
     case 2:
-      if (nop_opcode == NOP_OPCODE_MICROMIPS)
+      if (nop_opcode == NOP_OPCODE_MICROMIPS && !mips_opts.insn32)
        {
-         md_number_to_chars (p, micromips_nop16_insn.insn_opcode, 2);
-         p += 2;
+         p = write_compressed_insn (p, micromips_nop16_insn.insn_opcode, 2);
          break;
        }
       *p++ = '\0';
@@ -18731,7 +19035,6 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
   else
     as_warn (_(".end directive missing or unknown symbol"));
 
-#ifdef OBJ_ELF
   /* Create an expression to calculate the size of the function.  */
   if (p && cur_proc_ptr)
     {
@@ -18748,7 +19051,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     }
 
   /* Generate a .pdr section.  */
-  if (IS_ELF && !ECOFF_DEBUGGING && mips_flag_pdr)
+  if (!ECOFF_DEBUGGING && mips_flag_pdr)
     {
       segT saved_seg = now_seg;
       subsegT saved_subseg = now_subseg;
@@ -18780,7 +19083,6 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
 
       subseg_set (saved_seg, saved_subseg);
     }
-#endif /* OBJ_ELF */
 
   cur_proc_ptr = NULL;
 }
@@ -18838,8 +19140,9 @@ s_mips_ent (int aent)
 static void
 s_mips_frame (int ignore ATTRIBUTE_UNUSED)
 {
-#ifdef OBJ_ELF
-  if (IS_ELF && !ECOFF_DEBUGGING)
+  if (ECOFF_DEBUGGING)
+    s_ignore (ignore);
+  else
     {
       long val;
 
@@ -18867,9 +19170,6 @@ s_mips_frame (int ignore ATTRIBUTE_UNUSED)
 
       demand_empty_rest_of_line ();
     }
-  else
-#endif /* OBJ_ELF */
-    s_ignore (ignore);
 }
 
 /* The .fmask and .mask directives. If the mdebug section is present
@@ -18881,8 +19181,9 @@ s_mips_frame (int ignore ATTRIBUTE_UNUSED)
 static void
 s_mips_mask (int reg_type)
 {
-#ifdef OBJ_ELF
-  if (IS_ELF && !ECOFF_DEBUGGING)
+  if (ECOFF_DEBUGGING)
+    s_ignore (reg_type);
+  else
     {
       long mask, off;
 
@@ -18916,9 +19217,6 @@ s_mips_mask (int reg_type)
 
       demand_empty_rest_of_line ();
     }
-  else
-#endif /* OBJ_ELF */
-    s_ignore (reg_type);
 }
 
 /* A table describing all the processors gas knows about.  Names are
@@ -18929,159 +19227,148 @@ s_mips_mask (int reg_type)
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
   /* Entries for generic ISAs */
-  { "mips1",          MIPS_CPU_IS_ISA,         ISA_MIPS1,      CPU_R3000 },
-  { "mips2",          MIPS_CPU_IS_ISA,         ISA_MIPS2,      CPU_R6000 },
-  { "mips3",          MIPS_CPU_IS_ISA,         ISA_MIPS3,      CPU_R4000 },
-  { "mips4",          MIPS_CPU_IS_ISA,         ISA_MIPS4,      CPU_R8000 },
-  { "mips5",          MIPS_CPU_IS_ISA,         ISA_MIPS5,      CPU_MIPS5 },
-  { "mips32",         MIPS_CPU_IS_ISA,         ISA_MIPS32,     CPU_MIPS32 },
-  { "mips32r2",       MIPS_CPU_IS_ISA,         ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "mips64",         MIPS_CPU_IS_ISA,         ISA_MIPS64,     CPU_MIPS64 },
-  { "mips64r2",       MIPS_CPU_IS_ISA,         ISA_MIPS64R2,   CPU_MIPS64R2 },
+  { "mips1",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS1,    CPU_R3000 },
+  { "mips2",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS2,    CPU_R6000 },
+  { "mips3",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS3,    CPU_R4000 },
+  { "mips4",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS4,    CPU_R8000 },
+  { "mips5",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS5,    CPU_MIPS5 },
+  { "mips32",         MIPS_CPU_IS_ISA, 0,      ISA_MIPS32,   CPU_MIPS32 },
+  { "mips32r2",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "mips64",         MIPS_CPU_IS_ISA, 0,      ISA_MIPS64,   CPU_MIPS64 },
+  { "mips64r2",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS64R2, CPU_MIPS64R2 },
 
   /* MIPS I */
-  { "r3000",          0,                       ISA_MIPS1,      CPU_R3000 },
-  { "r2000",          0,                       ISA_MIPS1,      CPU_R3000 },
-  { "r3900",          0,                       ISA_MIPS1,      CPU_R3900 },
+  { "r3000",          0, 0,                    ISA_MIPS1,    CPU_R3000 },
+  { "r2000",          0, 0,                    ISA_MIPS1,    CPU_R3000 },
+  { "r3900",          0, 0,                    ISA_MIPS1,    CPU_R3900 },
 
   /* MIPS II */
-  { "r6000",          0,                       ISA_MIPS2,      CPU_R6000 },
+  { "r6000",          0, 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 },
+  { "r4000",          0, 0,                    ISA_MIPS3,    CPU_R4000 },
+  { "r4010",          0, 0,                    ISA_MIPS2,    CPU_R4010 },
+  { "vr4100",         0, 0,                    ISA_MIPS3,    CPU_VR4100 },
+  { "vr4111",         0, 0,                    ISA_MIPS3,    CPU_R4111 },
+  { "vr4120",         0, 0,                    ISA_MIPS3,    CPU_VR4120 },
+  { "vr4130",         0, 0,                    ISA_MIPS3,    CPU_VR4120 },
+  { "vr4181",         0, 0,                    ISA_MIPS3,    CPU_R4111 },
+  { "vr4300",         0, 0,                    ISA_MIPS3,    CPU_R4300 },
+  { "r4400",          0, 0,                    ISA_MIPS3,    CPU_R4400 },
+  { "r4600",          0, 0,                    ISA_MIPS3,    CPU_R4600 },
+  { "orion",          0, 0,                    ISA_MIPS3,    CPU_R4600 },
+  { "r4650",          0, 0,                    ISA_MIPS3,    CPU_R4650 },
+  { "r5900",          0, 0,                    ISA_MIPS3,    CPU_R5900 },
   /* ST Microelectronics Loongson 2E and 2F cores */
-  { "loongson2e",     0,                       ISA_MIPS3,   CPU_LOONGSON_2E },
-  { "loongson2f",     0,                       ISA_MIPS3,   CPU_LOONGSON_2F },
+  { "loongson2e",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2E },
+  { "loongson2f",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2F },
 
   /* MIPS IV */
-  { "r8000",          0,                       ISA_MIPS4,      CPU_R8000 },
-  { "r10000",         0,                       ISA_MIPS4,      CPU_R10000 },
-  { "r12000",         0,                       ISA_MIPS4,      CPU_R12000 },
-  { "r14000",         0,                       ISA_MIPS4,      CPU_R14000 },
-  { "r16000",         0,                       ISA_MIPS4,      CPU_R16000 },
-  { "vr5000",         0,                       ISA_MIPS4,      CPU_R5000 },
-  { "vr5400",         0,                       ISA_MIPS4,      CPU_VR5400 },
-  { "vr5500",         0,                       ISA_MIPS4,      CPU_VR5500 },
-  { "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 },
-  { "rm7000",         0,                       ISA_MIPS4,      CPU_RM7000 },
-  { "rm9000",         0,                       ISA_MIPS4,      CPU_RM9000 },
+  { "r8000",          0, 0,                    ISA_MIPS4,    CPU_R8000 },
+  { "r10000",         0, 0,                    ISA_MIPS4,    CPU_R10000 },
+  { "r12000",         0, 0,                    ISA_MIPS4,    CPU_R12000 },
+  { "r14000",         0, 0,                    ISA_MIPS4,    CPU_R14000 },
+  { "r16000",         0, 0,                    ISA_MIPS4,    CPU_R16000 },
+  { "vr5000",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "vr5400",         0, 0,                    ISA_MIPS4,    CPU_VR5400 },
+  { "vr5500",         0, 0,                    ISA_MIPS4,    CPU_VR5500 },
+  { "rm5200",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "rm5230",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "rm5231",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "rm5261",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "rm5721",         0, 0,                    ISA_MIPS4,    CPU_R5000 },
+  { "rm7000",         0, 0,                    ISA_MIPS4,    CPU_RM7000 },
+  { "rm9000",         0, 0,                    ISA_MIPS4,    CPU_RM9000 },
 
   /* MIPS 32 */
-  { "4kc",            0,                       ISA_MIPS32,     CPU_MIPS32 },
-  { "4km",            0,                       ISA_MIPS32,     CPU_MIPS32 },
-  { "4kp",            0,                       ISA_MIPS32,     CPU_MIPS32 },
-  { "4ksc",           MIPS_CPU_ASE_SMARTMIPS,  ISA_MIPS32,     CPU_MIPS32 },
+  { "4kc",            0, 0,                    ISA_MIPS32,   CPU_MIPS32 },
+  { "4km",            0, 0,                    ISA_MIPS32,   CPU_MIPS32 },
+  { "4kp",            0, 0,                    ISA_MIPS32,   CPU_MIPS32 },
+  { "4ksc",           0, ASE_SMARTMIPS,                ISA_MIPS32,   CPU_MIPS32 },
 
   /* MIPS 32 Release 2 */
-  { "4kec",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "4kem",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "4kep",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,  ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m4k",            0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m4kp",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m14k",           MIPS_CPU_ASE_MCU,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m14kc",          MIPS_CPU_ASE_MCU,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m14ke",          MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2 | MIPS_CPU_ASE_MCU,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "m14kec",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2 | MIPS_CPU_ASE_MCU,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kc",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kf2_1",        0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kf",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kf1_1",        0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "4kec",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "4kem",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "4kep",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "4ksd",           0, ASE_SMARTMIPS,                ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m4k",            0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m4kp",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m14k",           0, ASE_MCU,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m14kc",          0, ASE_MCU,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m14ke",          0, ASE_DSP | ASE_DSPR2 | ASE_MCU,
+                                               ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "m14kec",         0, ASE_DSP | ASE_DSPR2 | ASE_MCU,
+                                               ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kc",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kf2_1",        0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kf",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kf1_1",        0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
   /* Deprecated forms of the above.  */
-  { "24kfx",          0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kx",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kfx",          0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kx",           0, 0,                    ISA_MIPS32R2, CPU_MIPS32R2 },
   /* 24KE is a 24K with DSP ASE, other ASEs are optional.  */
-  { "24kec",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kef2_1",       MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kef",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kef1_1",       MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kec",          0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kef2_1",       0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kef",          0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kef1_1",       0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
   /* Deprecated forms of the above.  */
-  { "24kefx",         MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "24kex",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kefx",         0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "24kex",          0, ASE_DSP,              ISA_MIPS32R2, CPU_MIPS32R2 },
   /* 34K is a 24K with DSP and MT ASE, other ASEs are optional.  */
-  { "34kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kf2_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kf1_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kc",           0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "34kf2_1",        0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "34kf",           0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "34kf1_1",        0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   /* Deprecated forms of the above.  */
-  { "34kfx",          MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "34kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kfx",          0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "34kx",           0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  /* 34Kn is a 34kc without DSP.  */
+  { "34kn",           0, ASE_MT,               ISA_MIPS32R2, CPU_MIPS32R2 },
   /* 74K with DSP and DSPR2 ASE, other ASEs are optional.  */
-  { "74kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "74kf2_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "74kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "74kf1_1",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "74kf3_2",        MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kc",           0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "74kf2_1",        0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "74kf",           0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "74kf1_1",        0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "74kf3_2",        0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
   /* Deprecated forms of the above.  */
-  { "74kfx",          MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "74kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "74kfx",          0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "74kx",           0, ASE_DSP | ASE_DSPR2,  ISA_MIPS32R2, CPU_MIPS32R2 },
   /* 1004K cores are multiprocessor versions of the 34K.  */
-  { "1004kc",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "1004kf2_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "1004kf",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "1004kf1_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
-                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kc",         0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "1004kf2_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "1004kf",         0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "1004kf1_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
 
   /* MIPS 64 */
-  { "5kc",            0,                       ISA_MIPS64,     CPU_MIPS64 },
-  { "5kf",            0,                       ISA_MIPS64,     CPU_MIPS64 },
-  { "20kc",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
-  { "25kf",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
+  { "5kc",            0, 0,                    ISA_MIPS64,   CPU_MIPS64 },
+  { "5kf",            0, 0,                    ISA_MIPS64,   CPU_MIPS64 },
+  { "20kc",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
+  { "25kf",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
 
   /* Broadcom SB-1 CPU core */
-  { "sb1",            MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
-                                               ISA_MIPS64,     CPU_SB1 },
+  { "sb1",            0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
   /* Broadcom SB-1A CPU core */
-  { "sb1a",           MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
-                                               ISA_MIPS64,     CPU_SB1 },
+  { "sb1a",           0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
   
-  { "loongson3a",     0,                       ISA_MIPS64,     CPU_LOONGSON_3A },
+  { "loongson3a",     0, 0,                    ISA_MIPS64,   CPU_LOONGSON_3A },
 
   /* MIPS 64 Release 2 */
 
   /* Cavium Networks Octeon CPU core */
-  { "octeon",        0,      ISA_MIPS64R2,   CPU_OCTEON },
-  { "octeon+",       0,      ISA_MIPS64R2,   CPU_OCTEONP },
-  { "octeon2",       0,      ISA_MIPS64R2,   CPU_OCTEON2 },
+  { "octeon",        0, 0,                     ISA_MIPS64R2, CPU_OCTEON },
+  { "octeon+",       0, 0,                     ISA_MIPS64R2, CPU_OCTEONP },
+  { "octeon2",       0, 0,                     ISA_MIPS64R2, CPU_OCTEON2 },
 
   /* RMI Xlr */
-  { "xlr",           0,      ISA_MIPS64,     CPU_XLR },
+  { "xlr",           0, 0,                     ISA_MIPS64,   CPU_XLR },
+
+  /* Broadcom XLP.
+     XLP is mostly like XLR, with the prominent exception that it is
+     MIPS64R2 rather than MIPS64.  */
+  { "xlp",           0, 0,                     ISA_MIPS64R2, CPU_XLR },
 
   /* End marker */
-  { NULL, 0, 0, 0 }
+  { NULL, 0, 0, 0, 0 }
 };
 
 
@@ -19305,6 +19592,12 @@ MIPS options:\n\
 -mmcu                  generate MCU instructions\n\
 -mno-mcu               do not generate MCU instructions\n"));
   fprintf (stream, _("\
+-mvirt                 generate Virtualization instructions\n\
+-mno-virt              do not generate Virtualization instructions\n"));
+  fprintf (stream, _("\
+-minsn32               only generate 32-bit microMIPS instructions\n\
+-mno-insn32            generate all microMIPS instructions\n"));
+  fprintf (stream, _("\
 -mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
 -mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
@@ -19323,9 +19616,17 @@ MIPS options:\n\
 -msoft-float           do not allow floating-point instructions\n\
 -msingle-float         only allow 32-bit floating-point operations\n\
 -mdouble-float         allow 32-bit and 64-bit floating-point operations\n\
---[no-]construct-floats [dis]allow floating point values to be constructed\n"
-                    ));
-#ifdef OBJ_ELF
+--[no-]construct-floats        [dis]allow floating point values to be constructed\n\
+--[no-]relax-branch    [dis]allow out-of-range branches to be relaxed\n\
+-mnan=ENCODING         select an IEEE 754 NaN encoding convention, either of:\n"));
+
+  first = 1;
+
+  show (stream, "legacy", &column, &first);
+  show (stream, "2008", &column, &first);
+
+  fputc ('\n', stream);
+
   fprintf (stream, _("\
 -KPIC, -call_shared    generate SVR4 position independent code\n\
 -call_nonpic           generate non-PIC code that can operate with DSOs\n\
@@ -19351,7 +19652,6 @@ MIPS options:\n\
 -32                    create o32 ABI object file (default)\n\
 -n32                   create n32 ABI object file\n\
 -64                    create 64 ABI object file\n"));
-#endif
 }
 
 #ifdef TE_IRIX