gas/
[external/binutils.git] / gas / config / tc-mips.c
index df1a5a0..4e878c8 100644 (file)
 #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 {
@@ -245,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.  */
@@ -282,12 +272,15 @@ 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 */ 0, /* 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,
+  /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE,
+  /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
   /* soft_float */ FALSE, /* single_float */ FALSE
 };
 
@@ -542,6 +535,10 @@ static int mips_32bitmode = 0;
 #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;
@@ -696,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
@@ -718,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
@@ -778,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[] =
 {
@@ -818,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
 };
@@ -1286,7 +1279,7 @@ 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);
@@ -1320,6 +1313,7 @@ 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);
@@ -1428,6 +1422,8 @@ enum options
     OPTION_GP64,
     OPTION_RELAX_BRANCH,
     OPTION_NO_RELAX_BRANCH,
+    OPTION_INSN32,
+    OPTION_NO_INSN32,
     OPTION_MSHARED,
     OPTION_MNO_SHARED,
     OPTION_MSYM32,
@@ -1437,7 +1433,6 @@ enum options
     OPTION_SINGLE_FLOAT,
     OPTION_DOUBLE_FLOAT,
     OPTION_32,
-#ifdef OBJ_ELF
     OPTION_CALL_SHARED,
     OPTION_CALL_NONPIC,
     OPTION_NON_SHARED,
@@ -1450,7 +1445,7 @@ enum options
     OPTION_PDR,
     OPTION_NO_PDR,
     OPTION_MVXWORKS_PIC,
-#endif /* OBJ_ELF */
+    OPTION_NAN,
     OPTION_END_OF_ENUM
   };
 
@@ -1536,6 +1531,8 @@ struct option md_longopts[] =
   {"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},
@@ -1551,7 +1548,6 @@ struct option md_longopts[] =
   {"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},
@@ -1565,7 +1561,7 @@ struct option md_longopts[] =
   {"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 */
+  {"mnan", required_argument, NULL, OPTION_NAN},
 
   {NULL, no_argument, NULL, 0}
 };
@@ -1690,6 +1686,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"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.  */
@@ -1813,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};
 
@@ -1838,12 +1836,10 @@ static unsigned int forced_insn_length;
 
 static bfd_boolean mips_assembling_insn;
 
-#ifdef OBJ_ELF
 /* 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.  */
 
@@ -1860,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)
@@ -2596,6 +2588,19 @@ reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
   return ok && reglist != 0;
 }
 
+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.  */
 
@@ -2656,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)
@@ -2851,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);
+      }
+    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);
       }
-    }
-#endif /* OBJ_ELF */
+
+    subseg_set (seg, subseg);
+  }
 
   if (! ECOFF_DEBUGGING)
     md_obj_begin ();
@@ -2964,9 +2971,6 @@ 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;
@@ -2991,14 +2995,12 @@ md_assemble (char *str)
       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);
@@ -3097,6 +3099,13 @@ 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.  */
 
@@ -3222,14 +3231,12 @@ 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;
 }
@@ -3247,15 +3254,10 @@ mips_compressed_mark_label (symbolS *label)
 {
   gas_assert (HAVE_CODE_COMPRESSION);
 
-#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 (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
@@ -3513,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);
@@ -4411,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
@@ -4703,7 +4700,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   method = get_append_method (ip, address_expr, reloc_type);
   branch_disp = method == APPEND_SWAP ? insn_length (history) : 0;
 
-#ifdef OBJ_ELF
   dwarf2_emit_insn (0);
   /* We want MIPS16 and microMIPS debug info to use ISA-encoded addresses,
      so "move" the instruction address accordingly.
@@ -4717,7 +4713,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
      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);
-#endif
 
   relax32 = (mips_relax_branch
             /* Don't try branch relaxation within .set nomacro, or within
@@ -4854,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]);
@@ -5256,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])
 
@@ -5288,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
@@ -5429,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':
@@ -5566,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 '|':
@@ -5586,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':
@@ -5695,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':
@@ -5797,8 +5780,10 @@ macro_build_jalr (expressionS *ep, int cprestore)
     }
   if (mips_opts.micromips)
     {
-      jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
+      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
@@ -6479,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
@@ -6675,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;
@@ -6702,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;
@@ -6755,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
@@ -6774,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;
@@ -6795,11 +6823,10 @@ macro (struct mips_cl_insn *ip)
   int imm = 0;
   int ust = 0;
   int lp = 0;
-  int ab = 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);
 
@@ -6817,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)
     {
@@ -7000,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.  */
@@ -7040,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 */
@@ -7164,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"));
@@ -7593,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;
        }
 
@@ -8175,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:
@@ -8204,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:
@@ -8228,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:
@@ -8239,6 +8227,7 @@ macro (struct mips_cl_insn *ip)
        {
          s = jals ? "jalrs" : "jalr";
          if (mips_opts.micromips
+             && !mips_opts.insn32
              && dreg == RA
              && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
            macro_build (NULL, s, "mj", sreg);
@@ -8253,9 +8242,12 @@ 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
+             && !mips_opts.insn32
              && dreg == RA
              && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
            macro_build (NULL, s, "mj", sreg);
@@ -8294,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:
@@ -8436,146 +8433,108 @@ macro (struct mips_cl_insn *ip)
       break;
 
     case M_LBUE_AB:
-      ab = 1;
-    case M_LBUE_OB:
       s = "lbue";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LHUE_AB:
-      ab = 1;
-    case M_LHUE_OB:
       s = "lhue";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LBE_AB:
-      ab = 1;
-    case M_LBE_OB:
       s = "lbe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LHE_AB:
-      ab = 1;
-    case M_LHE_OB:
       s = "lhe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LLE_AB:
-      ab = 1;
-    case M_LLE_OB:
       s = "lle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWE_AB:
-      ab = 1;
-    case M_LWE_OB:
       s = "lwe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWLE_AB:
-      ab = 1;
-    case M_LWLE_OB:
       s = "lwle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWRE_AB:
-      ab = 1;
-    case M_LWRE_OB:
       s = "lwre";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SBE_AB:
-      ab = 1;
-    case M_SBE_OB:
       s = "sbe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SCE_AB:
-      ab = 1;
-    case M_SCE_OB:
       s = "sce";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SHE_AB:
-      ab = 1;
-    case M_SHE_OB:
       s = "she";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWE_AB:
-      ab = 1;
-    case M_SWE_OB:
       s = "swe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWLE_AB:
-      ab = 1;
-    case M_SWLE_OB:
       s = "swle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWRE_AB:
-      ab = 1;
-    case M_SWRE_OB:
       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)";
       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)";
       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)";
@@ -8583,15 +8542,12 @@ 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;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8599,7 +8555,6 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_LWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "lwc3";
       fmt = "E,o(b)";
@@ -8607,29 +8562,22 @@ 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;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LWR_AB:
-      ab = 1;
-    case M_LWR_OB:
       s = "lwr";
       fmt = MEM12_FMT;
       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;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8637,57 +8585,43 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_LQC2_AB:
-      ab = 1;
       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;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LDR_AB:
-      ab = 1;
-    case M_LDR_OB:
       s = "ldr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LL_AB:
-      ab = 1;
-    case M_LL_OB:
       s = "ll";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LLD_AB:
-      ab = 1;
-    case M_LLD_OB:
       s = "lld";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LWU_AB:
-      ab = 1;
-    case M_LWU_OB:
       s = "lwu";
       fmt = MEM12_FMT;
       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)";
@@ -8695,8 +8629,6 @@ macro (struct mips_cl_insn *ip)
       lp = 1;
       goto ld;
     case M_LDP_AB:
-      ab = 1;
-    case M_LDP_OB:
       gas_assert (mips_opts.micromips);
       s = "ldp";
       fmt = "t,~(b)";
@@ -8704,16 +8636,12 @@ macro (struct mips_cl_insn *ip)
       lp = 1;
       goto ld;
     case M_LWM_AB:
-      ab = 1;
-    case M_LWM_OB:
       gas_assert (mips_opts.micromips);
       s = "lwm";
       fmt = "n,~(b)";
       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)";
@@ -8729,22 +8657,18 @@ macro (struct mips_cl_insn *ip)
       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)";
@@ -8752,15 +8676,12 @@ 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;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8768,7 +8689,6 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_SWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "swc3";
       fmt = "E,o(b)";
@@ -8776,71 +8696,52 @@ 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;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SWR_AB:
-      ab = 1;
-    case M_SWR_OB:
       s = "swr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SC_AB:
-      ab = 1;
-    case M_SC_OB:
       s = "sc";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SCD_AB:
-      ab = 1;
-    case M_SCD_OB:
       s = "scd";
       fmt = MEM12_FMT;
       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)";
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_CACHEE_AB:
-      ab = 1;
-    case M_CACHEE_OB:
       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)";
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_PREFE_AB:
-      ab = 1;
-    case M_PREFE_OB:
       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;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8848,14 +8749,12 @@ macro (struct mips_cl_insn *ip)
       coproc = 1;
       goto ld_st;
     case M_SQC2_AB:
-      ab = 1;
       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)";
@@ -8863,46 +8762,34 @@ 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;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SDR_AB:
-      ab = 1;
-    case M_SDR_OB:
       s = "sdr";
       fmt = MEM12_FMT;
       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)";
       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)";
       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)";
       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)";
@@ -8910,8 +8797,41 @@ macro (struct mips_cl_insn *ip)
 
     ld_st:
       tempreg = AT;
-      used_at = 1;
     ld_noat:
+      if (small_offset_p (0, align, 16))
+       {
+         /* 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)
        {
@@ -8932,79 +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 ((offbits == 0 || offbits == 16)
-             && !IS_SEXT_16BIT_NUM (expr1.X_add_number))
-           {
-             expr1.X_add_number = ((expr1.X_add_number + 0x8000)
-                                   & ~(bfd_vma) 0xffff);
-             hipart = 1;
-           }
-         else if (offbits == 12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number))
-           {
-             expr1.X_add_number = ((expr1.X_add_number + 0x800)
-                                   & ~(bfd_vma) 0xfff);
-             hipart = 1;
-           }
-         else if (offbits == 9 && !IS_SEXT_9BIT_NUM (expr1.X_add_number))
-           {
-             expr1.X_add_number = ((expr1.X_add_number + 0x100)
-                                   & ~(bfd_vma) 0x1ff);
-             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;
-           }
+         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 (offbits == 16)
-           macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
+           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 (offbits != 16)
        {
          /* The 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;
+            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)
        {
@@ -9306,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);
@@ -9444,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 (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || 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
        {
@@ -9468,47 +9362,15 @@ macro (struct mips_cl_insn *ip)
              macro_build_lui (&offset_expr, AT);
            }
 
-         if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || 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 (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
-      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 (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
-      /* 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:
@@ -9574,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)
        {
@@ -9590,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
@@ -9649,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.  */
@@ -9789,36 +9697,13 @@ 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";
       offbits = 0;
       fmt = "t,(b)";
       goto ld_st;
     case M_SAAD_AB:
-      ab = 1;
-    case M_SAAD_OB:
       s = "saad";
       offbits = 0;
       fmt = "t,(b)";
@@ -9856,13 +9741,24 @@ macro (struct mips_cl_insn *ip)
       gas_assert (!mips_opts.micromips);
       /* 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:
@@ -10463,56 +10359,42 @@ 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";
       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";
       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";
       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";
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -10520,32 +10402,26 @@ macro (struct mips_cl_insn *ip)
       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 (offbits == 12
-              && (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;
@@ -10563,21 +10439,22 @@ macro (struct mips_cl_insn *ip)
 
       if (!target_big_endian)
        ep->X_add_number += off;
-      if (offbits != 12)
-       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 (offbits != 12)
-       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)
@@ -10592,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);
 
@@ -10607,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);
        }
@@ -10901,8 +10781,6 @@ 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;
@@ -10910,8 +10788,6 @@ validate_mips_insn (const struct mips_opcode *opc)
          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;
@@ -10924,6 +10800,7 @@ 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:
@@ -10985,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;
@@ -11081,11 +10956,11 @@ 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 "
@@ -11127,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;
@@ -11286,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)
@@ -11304,7 +11180,7 @@ 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;
@@ -11422,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);
@@ -11430,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;
@@ -11465,8 +11350,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case '3':
-             /* DSP 3-bit unsigned immediate in bit 13 (for standard MIPS
-                code) or 21 (for microMIPS code).  */
+             /* 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);
@@ -11484,8 +11369,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case '4':
-             /* DSP 4-bit unsigned immediate in bit 12 (for standard MIPS
-                code) or 21 (for microMIPS code).  */
+             /* 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);
@@ -11503,8 +11388,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case '5':
-             /* DSP 8-bit unsigned immediate in bit 13 (for standard MIPS
-                code) or 16 (for microMIPS code).  */
+             /* 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);
@@ -11522,8 +11407,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case '6':
-             /* DSP 5-bit unsigned immediate in bit 16 (for standard MIPS
-                code) or 21 (for microMIPS code).  */
+             /* 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);
@@ -11540,7 +11425,9 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              }
              continue;
 
-           case '7': /* Four DSP accumulators in bits 11,12.  */
+           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')
                {
@@ -11588,8 +11475,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              break;
 
            case '0':
-             /* DSP 6-bit signed immediate in bit 16 (for standard MIPS
-                code) or 20 (for microMIPS code).  */
+             /* 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);
@@ -11795,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)
                {
@@ -11946,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);
@@ -11961,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]))
@@ -12035,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;
@@ -12058,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);
@@ -12074,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)"),
@@ -12194,10 +12064,15 @@ 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.  */
@@ -12207,7 +12082,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))
@@ -12239,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
@@ -12249,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))
@@ -12673,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.  */
@@ -12729,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));
@@ -12751,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);
@@ -12797,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':
@@ -12909,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)
@@ -12917,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
                  {
@@ -12962,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);
@@ -12994,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;
@@ -13003,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.  */
@@ -13025,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"));
                    }
                }
@@ -13073,17 +12938,18 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case 'u':           /* Upper 16 bits.  */
-             *imm_reloc = BFD_RELOC_LO16;
-             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;
@@ -13195,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':
@@ -13318,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 != ',')
                          {
-                           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;
+                           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)
+                         {
+                           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':
@@ -13435,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;
@@ -13962,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)
@@ -14030,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);
 
@@ -14059,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;
@@ -14087,19 +13929,31 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  offsetT value;
 
                  /* Stuff the immediate value in now, if we can.  */
-                 if (imm_expr.X_op == O_constant
-                     && *imm_reloc > BFD_RELOC_UNUSED
-                     && insn->pinfo != INSN_MACRO
-                     && calculate_reloc (*offset_reloc,
-                                         imm_expr.X_add_number, &value))
+                 if (insn->pinfo == INSN_MACRO)
+                   {
+                     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, *imm_reloc - BFD_RELOC_UNUSED,
-                                   *offset_reloc, value, forced_insn_length,
-                                   &ip->insn_opcode);
-                     imm_expr.X_op = O_absent;
-                     *imm_reloc = BFD_RELOC_UNUSED;
+                     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;
                    }
+                 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;
                }
@@ -14270,24 +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->insn_opcode |= MIPS16_EXTEND;
-                   }
-                 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 '>':
@@ -14295,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.  */
@@ -14306,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;
                    }
 
@@ -14318,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;
 
@@ -14336,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;
 
@@ -14352,7 +14196,18 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              s = expr_end;
              continue;
 
+           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;
@@ -14819,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},
@@ -14841,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}
 };
 
@@ -14995,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;
@@ -15010,7 +14862,6 @@ static int support_64bit_objects(void)
   free (list);
   return yes;
 }
-#endif /* OBJ_ELF */
 
 /* Set STRING_PTR (either &mips_arch_string or &mips_tune_string) to
    NEW_VALUE.  Warn if another value was already specified.  Note:
@@ -15248,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;
@@ -15264,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;
@@ -15304,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);
@@ -15314,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;
@@ -15374,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)
@@ -15402,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;
@@ -15412,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;
@@ -15432,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;
@@ -15629,14 +15459,7 @@ mips_after_parse_args (void)
   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
@@ -16229,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 ();
 
@@ -16258,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;
     }
@@ -16299,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;
@@ -16308,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)
@@ -16370,7 +16177,6 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
 
   if (now_seg->name != section_name)
     free (section_name);
-#endif /* OBJ_ELF */
 }
 
 void
@@ -16725,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;
@@ -17344,6 +17154,30 @@ s_insn (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* Handle the .nan pseudo-op.  */
+
+static void
+s_nan (int ignore ATTRIBUTE_UNUSED)
+{
+  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
@@ -17438,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));
 }
@@ -17555,11 +17386,8 @@ pic_need_relax (symbolS *sym, asection *segtype)
          && !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)));
 }
 
 
@@ -18076,7 +17904,6 @@ mips_fix_adjustable (fixS *fixp)
          || 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
@@ -18119,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;
 }
@@ -18159,14 +17984,6 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       /* 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;
@@ -18577,10 +18394,7 @@ 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 - fragp->fr_literal, 4, l, 0, TRUE,
@@ -18814,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.  */
@@ -18826,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++)
@@ -18843,8 +18652,6 @@ 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
@@ -18877,9 +18684,7 @@ void
 mips_define_label (symbolS *sym)
 {
   mips_record_label (sym);
-#ifdef OBJ_ELF
   dwarf2_emit_label (sym);
-#endif
 }
 
 /* This function is called by tc_new_dot_label whenever a new dot symbol
@@ -18893,8 +18698,6 @@ mips_add_dot_label (symbolS *sym)
     mips_compressed_mark_label (sym);
 }
 \f
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-
 /* Some special processing for a MIPS ELF file.  */
 
 void
@@ -18974,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;
@@ -19065,7 +18869,7 @@ 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)
        {
          p = write_compressed_insn (p, micromips_nop16_insn.insn_opcode, 2);
          break;
@@ -19231,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)
     {
@@ -19248,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;
@@ -19280,7 +19083,6 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
 
       subseg_set (saved_seg, saved_subseg);
     }
-#endif /* OBJ_ELF */
 
   cur_proc_ptr = NULL;
 }
@@ -19338,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;
 
@@ -19367,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
@@ -19381,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;
 
@@ -19416,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
@@ -19797,6 +19595,9 @@ MIPS options:\n\
 -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\
@@ -19816,9 +19617,16 @@ MIPS options:\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\
---[no-]relax-branch    [dis]allow out-of-range branches to be relaxed\n"
-                    ));
-#ifdef OBJ_ELF
+--[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\
@@ -19844,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