Add support for MIPS R6.
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 1c950a7a4583215c6a8f2149508ddc02ba862d10..8d4a80bb182a121a0709b25c66774511c9a262d1 100644 (file)
@@ -42,6 +42,8 @@ typedef char static_assert2[sizeof (valueT) < 8 ? -1 : 1];
 #define DBG(x)
 #endif
 
+#define streq(a, b)           (strcmp (a, b) == 0)
+
 #define SKIP_SPACE_TABS(S) \
   do { while (*(S) == ' ' || *(S) == '\t') ++(S); } while (0)
 
@@ -87,6 +89,7 @@ int mips_flag_pdr = TRUE;
 #include "ecoff.h"
 
 static char *mips_regmask_frag;
+static char *mips_flags_frag;
 
 #define ZERO 0
 #define ATREG 1
@@ -239,8 +242,8 @@ struct mips_set_options
   /* 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.  */
-  int gp32;
-  int fp32;
+  int gp;
+  int fp;
   /* MIPS architecture (CPU) type.  Changed by .set arch=FOO, the -march
      command line option, and the default CPU.  */
   int arch;
@@ -255,40 +258,45 @@ struct mips_set_options
      Changed by .set singlefloat or .set doublefloat, command-line options
      -msingle-float or -mdouble-float.  The default is false.  */
   bfd_boolean single_float;
-};
 
-/* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
-   -1 to indicate that they have not been initialized.  */
+  /* 1 if single-precision operations on odd-numbered registers are
+     allowed.  */
+  int oddspreg;
+};
 
-/* True if -mgp32 was passed.  */
-static int file_mips_gp32 = -1;
+/* Specifies whether module level options have been checked yet.  */
+static bfd_boolean file_mips_opts_checked = FALSE;
 
-/* True if -mfp32 was passed.  */
-static int file_mips_fp32 = -1;
+/* Do we support nan2008?  0 if we don't, 1 if we do, and -1 if the
+   value has not been initialized.  Changed by `.nan legacy' and
+   `.nan 2008', and the -mnan=legacy and -mnan=2008 command line
+   options, and the default CPU.  */
+static int mips_nan2008 = -1;
 
-/* 1 if -msoft-float, 0 if -mhard-float.  The default is 0.  */
-static int file_mips_soft_float = 0;
+/* This is the struct we use to hold the module level set of options.
+   Note that we must set the isa field to ISA_UNKNOWN and the ASE, gp and
+   fp fields to -1 to indicate that they have not been initialized.  */
 
-/* 1 if -msingle-float, 0 if -mdouble-float.  The default is 0.   */
-static int file_mips_single_float = 0;
+static struct mips_set_options file_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, /* insn32 */ FALSE,
+  /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1
+};
 
-/* True if -mnan=2008, false if -mnan=legacy.  */
-static bfd_boolean mips_flag_nan2008 = FALSE;
+/* This is similar to file_mips_opts, but for the current set of options.  */
 
 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, /* insn32 */ FALSE,
-  /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
-  /* soft_float */ FALSE, /* single_float */ FALSE
+  /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE,
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1
 };
 
-/* The set of ASEs that were selected on the command line, either
-   explicitly via ASE options or implicitly through things like -march.  */
-static unsigned int file_ase;
-
 /* Which bits of file_ase were explicitly set or cleared by ASE options.  */
 static unsigned int file_ase_explicit;
 
@@ -298,9 +306,6 @@ static unsigned int file_ase_explicit;
 unsigned long mips_gprmask;
 unsigned long mips_cprmask[4];
 
-/* MIPS ISA we are using for this output file.  */
-static int file_mips_isa = ISA_UNKNOWN;
-
 /* True if any MIPS16 code was produced.  */
 static int file_ase_mips16;
 
@@ -329,7 +334,6 @@ static int file_ase_micromips;
 #endif
 
 /* The argument of the -march= flag.  The architecture we are assembling.  */
-static int file_mips_arch = CPU_UNKNOWN;
 static const char *mips_arch_string;
 
 /* The argument of the -mtune= flag.  The architecture for which we
@@ -349,6 +353,10 @@ static int mips_32bitmode = 0;
    || (ABI) == N64_ABI                 \
    || (ABI) == O64_ABI)
 
+#define ISA_IS_R6(ISA)                 \
+  ((ISA) == ISA_MIPS32R6               \
+   || (ISA) == ISA_MIPS64R6)
+
 /*  Return true if ISA supports 64 bit wide gp registers.  */
 #define ISA_HAS_64BIT_REGS(ISA)                \
   ((ISA) == ISA_MIPS3                  \
@@ -357,7 +365,8 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS64              \
    || (ISA) == ISA_MIPS64R2            \
    || (ISA) == ISA_MIPS64R3            \
-   || (ISA) == ISA_MIPS64R5)
+   || (ISA) == ISA_MIPS64R5            \
+   || (ISA) == ISA_MIPS64R6)
 
 /*  Return true if ISA supports 64 bit wide float registers.  */
 #define ISA_HAS_64BIT_FPRS(ISA)                \
@@ -367,10 +376,12 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS32R2            \
    || (ISA) == ISA_MIPS32R3            \
    || (ISA) == ISA_MIPS32R5            \
+   || (ISA) == ISA_MIPS32R6            \
    || (ISA) == ISA_MIPS64              \
    || (ISA) == ISA_MIPS64R2            \
    || (ISA) == ISA_MIPS64R3            \
-   || (ISA) == ISA_MIPS64R5            )
+   || (ISA) == ISA_MIPS64R5            \
+   || (ISA) == ISA_MIPS64R6)
 
 /* Return true if ISA supports 64-bit right rotate (dror et al.)
    instructions.  */
@@ -378,6 +389,7 @@ static int mips_32bitmode = 0;
   ((ISA) == ISA_MIPS64R2               \
    || (ISA) == ISA_MIPS64R3            \
    || (ISA) == ISA_MIPS64R5            \
+   || (ISA) == ISA_MIPS64R6            \
    || (mips_opts.micromips             \
        && ISA_HAS_64BIT_REGS (ISA))    \
    )
@@ -388,23 +400,29 @@ static int mips_32bitmode = 0;
   ((ISA) == ISA_MIPS32R2               \
    || (ISA) == ISA_MIPS32R3            \
    || (ISA) == ISA_MIPS32R5            \
+   || (ISA) == ISA_MIPS32R6            \
    || (ISA) == ISA_MIPS64R2            \
    || (ISA) == ISA_MIPS64R3            \
    || (ISA) == ISA_MIPS64R5            \
+   || (ISA) == ISA_MIPS64R6            \
    || (mips_opts.ase & ASE_SMARTMIPS)  \
    || mips_opts.micromips              \
    )
 
 /* Return true if ISA supports single-precision floats in odd registers.  */
-#define ISA_HAS_ODD_SINGLE_FPR(ISA)    \
-  ((ISA) == ISA_MIPS32                 \
-   || (ISA) == ISA_MIPS32R2            \
-   || (ISA) == ISA_MIPS32R3            \
-   || (ISA) == ISA_MIPS32R5            \
-   || (ISA) == ISA_MIPS64              \
-   || (ISA) == ISA_MIPS64R2            \
-   || (ISA) == ISA_MIPS64R3            \
-   || (ISA) == ISA_MIPS64R5)
+#define ISA_HAS_ODD_SINGLE_FPR(ISA, CPU)\
+  (((ISA) == ISA_MIPS32                        \
+    || (ISA) == ISA_MIPS32R2           \
+    || (ISA) == ISA_MIPS32R3           \
+    || (ISA) == ISA_MIPS32R5           \
+    || (ISA) == ISA_MIPS32R6           \
+    || (ISA) == ISA_MIPS64             \
+    || (ISA) == ISA_MIPS64R2           \
+    || (ISA) == ISA_MIPS64R3           \
+    || (ISA) == ISA_MIPS64R5           \
+    || (ISA) == ISA_MIPS64R6           \
+    || (CPU) == CPU_R5900)             \
+   && (CPU) != CPU_LOONGSON_3A)
 
 /* Return true if ISA supports move to/from high part of a 64-bit
    floating-point register. */
@@ -412,18 +430,37 @@ static int mips_32bitmode = 0;
   ((ISA) == ISA_MIPS32R2               \
    || (ISA) == ISA_MIPS32R3            \
    || (ISA) == ISA_MIPS32R5            \
+   || (ISA) == ISA_MIPS32R6            \
    || (ISA) == ISA_MIPS64R2            \
    || (ISA) == ISA_MIPS64R3            \
-   || (ISA) == ISA_MIPS64R5)
+   || (ISA) == ISA_MIPS64R5            \
+   || (ISA) == ISA_MIPS64R6)
 
-#define HAVE_32BIT_GPRS                                   \
-    (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
+/*  Return true if ISA supports legacy NAN.  */
+#define ISA_HAS_LEGACY_NAN(ISA)                \
+  ((ISA) == ISA_MIPS1                  \
+   || (ISA) == ISA_MIPS2               \
+   || (ISA) == ISA_MIPS3               \
+   || (ISA) == ISA_MIPS4               \
+   || (ISA) == ISA_MIPS5               \
+   || (ISA) == ISA_MIPS32              \
+   || (ISA) == ISA_MIPS32R2            \
+   || (ISA) == ISA_MIPS32R3            \
+   || (ISA) == ISA_MIPS32R5            \
+   || (ISA) == ISA_MIPS64              \
+   || (ISA) == ISA_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5)
 
-#define HAVE_32BIT_FPRS                            \
-    (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
+#define GPR_SIZE \
+    (mips_opts.gp == 64 && !ISA_HAS_64BIT_REGS (mips_opts.isa) \
+     ? 32 \
+     : mips_opts.gp)
 
-#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
-#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
+#define FPR_SIZE \
+    (mips_opts.fp == 64 && !ISA_HAS_64BIT_FPRS (mips_opts.isa) \
+     ? 32 \
+     : mips_opts.fp)
 
 #define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
 
@@ -434,7 +471,7 @@ static int mips_32bitmode = 0;
 
 /* The ABI-derived address size.  */
 #define HAVE_64BIT_ADDRESSES \
-  (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
+  (GPR_SIZE == 64 && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
 #define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES)
 
 /* The size of symbolic constants (i.e., expressions of the form
@@ -499,10 +536,12 @@ static int mips_32bitmode = 0;
    || mips_opts.isa == ISA_MIPS32R2                   \
    || mips_opts.isa == ISA_MIPS32R3                   \
    || mips_opts.isa == ISA_MIPS32R5                   \
+   || mips_opts.isa == ISA_MIPS32R6                   \
    || mips_opts.isa == ISA_MIPS64                     \
    || mips_opts.isa == ISA_MIPS64R2                   \
    || mips_opts.isa == ISA_MIPS64R3                   \
    || mips_opts.isa == ISA_MIPS64R5                   \
+   || mips_opts.isa == ISA_MIPS64R6                   \
    || mips_opts.arch == CPU_R4010                     \
    || mips_opts.arch == CPU_R5900                     \
    || mips_opts.arch == CPU_R10000                    \
@@ -529,8 +568,8 @@ static int mips_32bitmode = 0;
 /* Whether the processor uses hardware interlocks to avoid delays
    required by coprocessor instructions, and thus does not require
    nops to be inserted.  This applies to instructions marked
-   INSN_LOAD_COPROC_DELAY, INSN_COPROC_MOVE_DELAY, and to delays
-   between instructions marked INSN_WRITE_COND_CODE and ones marked
+   INSN_LOAD_COPROC, INSN_COPROC_MOVE, and to delays between
+   instructions marked INSN_WRITE_COND_CODE and ones marked
    INSN_READ_COND_CODE.  These nops are only required at MIPS ISA
    levels I, II, and III and microMIPS mode instructions are always
    interlocked.  */
@@ -565,7 +604,7 @@ static int mips_32bitmode = 0;
   ((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_SMAX ((offsetT) (((valueT) 1 << (GPR_SIZE - 1)) - 1))
 #define GPR_SMIN (-GPR_SMAX - 1)
 
 /* MIPS PIC level.  */
@@ -1297,8 +1336,7 @@ 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_module (int);
 static void s_mips_ent (int);
 static void s_mips_end (int);
 static void s_mips_frame (int);
@@ -1311,6 +1349,7 @@ static bfd_boolean pic_need_relax (symbolS *, asection *);
 static int relaxed_branch_length (fragS *, asection *, int);
 static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
 static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
+static void file_mips_check_options (void);
 
 /* Table and functions used to map between CPU/ISA names, and
    ISA levels, and CPU numbers.  */
@@ -1347,9 +1386,11 @@ enum options
     OPTION_MIPS32R2,
     OPTION_MIPS32R3,
     OPTION_MIPS32R5,
+    OPTION_MIPS32R6,
     OPTION_MIPS64R2,
     OPTION_MIPS64R3,
     OPTION_MIPS64R5,
+    OPTION_MIPS64R6,
     OPTION_MIPS16,
     OPTION_NO_MIPS16,
     OPTION_MIPS3D,
@@ -1410,6 +1451,7 @@ enum options
     OPTION_CONSTRUCT_FLOATS,
     OPTION_NO_CONSTRUCT_FLOATS,
     OPTION_FP64,
+    OPTION_FPXX,
     OPTION_GP64,
     OPTION_RELAX_BRANCH,
     OPTION_NO_RELAX_BRANCH,
@@ -1437,6 +1479,8 @@ enum options
     OPTION_NO_PDR,
     OPTION_MVXWORKS_PIC,
     OPTION_NAN,
+    OPTION_ODD_SPREG,
+    OPTION_NO_ODD_SPREG,
     OPTION_END_OF_ENUM
   };
 
@@ -1456,9 +1500,11 @@ struct option md_longopts[] =
   {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
   {"mips32r3", no_argument, NULL, OPTION_MIPS32R3},
   {"mips32r5", no_argument, NULL, OPTION_MIPS32R5},
+  {"mips32r6", no_argument, NULL, OPTION_MIPS32R6},
   {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
   {"mips64r3", no_argument, NULL, OPTION_MIPS64R3},
   {"mips64r5", no_argument, NULL, OPTION_MIPS64R5},
+  {"mips64r6", no_argument, NULL, OPTION_MIPS64R6},
 
   /* Options which specify Application Specific Extensions (ASEs).  */
   {"mips16", no_argument, NULL, OPTION_MIPS16},
@@ -1529,6 +1575,7 @@ struct option md_longopts[] =
   {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
   {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
   {"mfp64", no_argument, NULL, OPTION_FP64},
+  {"mfpxx", no_argument, NULL, OPTION_FPXX},
   {"mgp64", no_argument, NULL, OPTION_GP64},
   {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
   {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
@@ -1542,6 +1589,8 @@ struct option md_longopts[] =
   {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
   {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
   {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+  {"modd-spreg", no_argument, NULL, OPTION_ODD_SPREG},
+  {"mno-odd-spreg", no_argument, NULL, OPTION_NO_ODD_SPREG},
 
   /* Strictly speaking this next option is ELF specific,
      but we allow it for other ports as well in order to
@@ -1595,59 +1644,74 @@ struct mips_ase
   int mips64_rev;
   int micromips32_rev;
   int micromips64_rev;
+
+  /* The architecture where the ASE was removed or -1 if the extension has not
+     been removed.  */
+  int rem_rev;
 };
 
 /* A table of all supported ASEs.  */
 static const struct mips_ase mips_ases[] = {
   { "dsp", ASE_DSP, ASE_DSP64,
     OPTION_DSP, OPTION_NO_DSP,
-    2, 2, 2, 2 },
+    2, 2, 2, 2,
+    -1 },
 
   { "dspr2", ASE_DSP | ASE_DSPR2, 0,
     OPTION_DSPR2, OPTION_NO_DSPR2,
-    2, 2, 2, 2 },
+    2, 2, 2, 2,
+    -1 },
 
   { "eva", ASE_EVA, 0,
     OPTION_EVA, OPTION_NO_EVA,
-    2, 2, 2, 2 },
+     2,  2,  2,  2,
+    -1 },
 
   { "mcu", ASE_MCU, 0,
     OPTION_MCU, OPTION_NO_MCU,
-    2, 2, 2, 2 },
+     2,  2,  2,  2,
+    -1 },
 
   /* Deprecated in MIPS64r5, but we don't implement that yet.  */
   { "mdmx", ASE_MDMX, 0,
     OPTION_MDMX, OPTION_NO_MDMX,
-    -1, 1, -1, -1 },
+    -1, 1, -1, -1,
+     6 },
 
   /* Requires 64-bit FPRs, so the minimum MIPS32 revision is 2.  */
   { "mips3d", ASE_MIPS3D, 0,
     OPTION_MIPS3D, OPTION_NO_MIPS3D,
-    2, 1, -1, -1 },
+    2, 1, -1, -1,
+    6 },
 
   { "mt", ASE_MT, 0,
     OPTION_MT, OPTION_NO_MT,
-    2, 2, -1, -1 },
+     2,  2, -1, -1,
+    -1 },
 
   { "smartmips", ASE_SMARTMIPS, 0,
     OPTION_SMARTMIPS, OPTION_NO_SMARTMIPS,
-    1, -1, -1, -1 },
+    1, -1, -1, -1,
+    6 },
 
   { "virt", ASE_VIRT, ASE_VIRT64,
     OPTION_VIRT, OPTION_NO_VIRT,
-    2, 2, 2, 2 },
+     2,  2,  2,  2,
+    -1 },
 
   { "msa", ASE_MSA, ASE_MSA64,
     OPTION_MSA, OPTION_NO_MSA,
-    2, 2, 2, 2 },
+     2,  2,  2,  2,
+    -1 },
 
   { "xpa", ASE_XPA, 0,
     OPTION_XPA, OPTION_NO_XPA,
-    2, 2, -1, -1 }
+     2,  2, -1, -1,
+    -1 },
 };
 
 /* The set of ASEs that require -mfp64.  */
-#define FP64_ASES (ASE_MIPS3D | ASE_MDMX)
+#define FP64_ASES (ASE_MIPS3D | ASE_MDMX | ASE_MSA)
 
 /* Groups of ASE_* flags that represent different revisions of an ASE.  */
 static const unsigned int mips_ase_groups[] = {
@@ -1696,6 +1760,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
   {"nan", s_nan, 0},
+  {"module", s_module, 0},
 
   /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
@@ -1763,6 +1828,7 @@ static const pseudo_typeS mips_nonecoff_pseudo_table[] =
 int
 mips_address_bytes (void)
 {
+  file_mips_check_options ();
   return HAVE_64BIT_ADDRESSES ? 8 : 4;
 }
 
@@ -1903,6 +1969,9 @@ mips_isa_rev (void)
   if (mips_opts.isa == ISA_MIPS32R5 || mips_opts.isa == ISA_MIPS64R5)
     return 5;
 
+  if (mips_opts.isa == ISA_MIPS32R6 || mips_opts.isa == ISA_MIPS64R6)
+    return 6;
+
   /* microMIPS implies revision 2 or above.  */
   if (mips_opts.micromips)
     return 2;
@@ -1954,8 +2023,18 @@ mips_check_isa_supports_ase (const struct mips_ase *ase)
        as_warn (_("the `%s' extension requires %s%d revision %d or greater"),
                 ase->name, base, size, min_rev);
     }
+  else if ((ase->rem_rev > 0 && mips_isa_rev () >= ase->rem_rev)
+          && (warned_isa & ase->flags) != ase->flags)
+    {
+      warned_isa |= ase->flags;
+      base = mips_opts.micromips ? "microMIPS" : "MIPS";
+      size = ISA_HAS_64BIT_REGS (mips_opts.isa) ? 64 : 32;
+      as_warn (_("the `%s' extension was removed in %s%d revision %d"),
+              ase->name, base, size, ase->rem_rev);
+    }
+
   if ((ase->flags & FP64_ASES)
-      && mips_opts.fp32
+      && mips_opts.fp != 64
       && (warned_fp32 & ase->flags) != ase->flags)
     {
       warned_fp32 |= ase->flags;
@@ -1983,14 +2062,15 @@ mips_check_isa_supports_ases (void)
    that were affected.  */
 
 static unsigned int
-mips_set_ase (const struct mips_ase *ase, bfd_boolean enabled_p)
+mips_set_ase (const struct mips_ase *ase, struct mips_set_options *opts,
+             bfd_boolean enabled_p)
 {
   unsigned int mask;
 
   mask = mips_ase_mask (ase->flags);
-  mips_opts.ase &= ~mask;
+  opts->ase &= ~mask;
   if (enabled_p)
-    mips_opts.ase |= ase->flags;
+    opts->ase |= ase->flags;
   return mask;
 }
 
@@ -3281,7 +3361,7 @@ validate_mips_insn (const struct mips_opcode *opcode,
              used_bits &= ~(mask & 0x700);
          }
        /* Skip prefix characters.  */
-       if (decode_operand && (*s == '+' || *s == 'm'))
+       if (decode_operand && (*s == '+' || *s == 'm' || *s == '-'))
          ++s;
        opno += 1;
        break;
@@ -3386,7 +3466,7 @@ md_begin (void)
       g_switch_value = 0;
     }
 
-  if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
+  if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
     as_warn (_("could not set architecture and machine"));
 
   op_hash = hash_new ();
@@ -3612,6 +3692,12 @@ md_begin (void)
        }
       }
 
+    sec = subseg_new (".MIPS.abiflags", (subsegT) 0);
+    bfd_set_section_flags (stdoutput, sec,
+                          SEC_READONLY | SEC_DATA | SEC_ALLOC | SEC_LOAD);
+    bfd_set_section_alignment (stdoutput, sec, 3);
+    mips_flags_frag = frag_more (sizeof (Elf_External_ABIFlags_v0));
+
     if (ECOFF_DEBUGGING)
       {
        sec = subseg_new (".mdebug", (subsegT) 0);
@@ -3631,19 +3717,263 @@ md_begin (void)
     subseg_set (seg, subseg);
   }
 
-  if (! ECOFF_DEBUGGING)
-    md_obj_begin ();
-
   if (mips_fix_vr4120)
     init_vr4120_conflicts ();
 }
 
-void
-md_mips_end (void)
+static inline void
+fpabi_incompatible_with (int fpabi, const char *what)
 {
-  mips_emit_delays ();
-  if (! ECOFF_DEBUGGING)
-    md_obj_end ();
+  as_warn (_(".gnu_attribute %d,%d is incompatible with `%s'"),
+          Tag_GNU_MIPS_ABI_FP, fpabi, what);
+}
+
+static inline void
+fpabi_requires (int fpabi, const char *what)
+{
+  as_warn (_(".gnu_attribute %d,%d requires `%s'"),
+          Tag_GNU_MIPS_ABI_FP, fpabi, what);
+}
+
+/* Check -mabi and register sizes against the specified FP ABI.  */
+static void
+check_fpabi (int fpabi)
+{
+  switch (fpabi)
+    {
+    case Val_GNU_MIPS_ABI_FP_DOUBLE:
+      if (file_mips_opts.soft_float)
+       fpabi_incompatible_with (fpabi, "softfloat");
+      else if (file_mips_opts.single_float)
+       fpabi_incompatible_with (fpabi, "singlefloat");
+      if (file_mips_opts.gp == 64 && file_mips_opts.fp == 32)
+       fpabi_incompatible_with (fpabi, "gp=64 fp=32");
+      else if (file_mips_opts.gp == 32 && file_mips_opts.fp == 64)
+       fpabi_incompatible_with (fpabi, "gp=32 fp=64");
+      break;
+
+    case Val_GNU_MIPS_ABI_FP_XX:
+      if (mips_abi != O32_ABI)
+       fpabi_requires (fpabi, "-mabi=32");
+      else if (file_mips_opts.soft_float)
+       fpabi_incompatible_with (fpabi, "softfloat");
+      else if (file_mips_opts.single_float)
+       fpabi_incompatible_with (fpabi, "singlefloat");
+      else if (file_mips_opts.fp != 0)
+       fpabi_requires (fpabi, "fp=xx");
+      break;
+
+    case Val_GNU_MIPS_ABI_FP_64A:
+    case Val_GNU_MIPS_ABI_FP_64:
+      if (mips_abi != O32_ABI)
+       fpabi_requires (fpabi, "-mabi=32");
+      else if (file_mips_opts.soft_float)
+       fpabi_incompatible_with (fpabi, "softfloat");
+      else if (file_mips_opts.single_float)
+       fpabi_incompatible_with (fpabi, "singlefloat");
+      else if (file_mips_opts.fp != 64)
+       fpabi_requires (fpabi, "fp=64");
+      else if (fpabi == Val_GNU_MIPS_ABI_FP_64 && !file_mips_opts.oddspreg)
+       fpabi_incompatible_with (fpabi, "nooddspreg");
+      else if (fpabi == Val_GNU_MIPS_ABI_FP_64A && file_mips_opts.oddspreg)
+       fpabi_requires (fpabi, "nooddspreg");
+      break;
+
+    case Val_GNU_MIPS_ABI_FP_SINGLE:
+      if (file_mips_opts.soft_float)
+       fpabi_incompatible_with (fpabi, "softfloat");
+      else if (!file_mips_opts.single_float)
+       fpabi_requires (fpabi, "singlefloat");
+      break;
+
+    case Val_GNU_MIPS_ABI_FP_SOFT:
+      if (!file_mips_opts.soft_float)
+       fpabi_requires (fpabi, "softfloat");
+      break;
+
+    case Val_GNU_MIPS_ABI_FP_OLD_64:
+      as_warn (_(".gnu_attribute %d,%d is no longer supported"),
+              Tag_GNU_MIPS_ABI_FP, fpabi);
+      break;
+
+    default:
+      as_warn (_(".gnu_attribute %d,%d is not a recognized"
+                " floating-point ABI"), Tag_GNU_MIPS_ABI_FP, fpabi);
+      break;
+    }
+}
+
+/* Perform consistency checks on the current options.  */
+
+static void
+mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
+{
+  /* Check the size of integer registers agrees with the ABI and ISA.  */
+  if (opts->gp == 64 && !ISA_HAS_64BIT_REGS (opts->isa))
+    as_bad (_("`gp=64' used with a 32-bit processor"));
+  else if (abi_checks
+          && opts->gp == 32 && ABI_NEEDS_64BIT_REGS (mips_abi))
+    as_bad (_("`gp=32' used with a 64-bit ABI"));
+  else if (abi_checks
+          && opts->gp == 64 && ABI_NEEDS_32BIT_REGS (mips_abi))
+    as_bad (_("`gp=64' used with a 32-bit ABI"));
+
+  /* Check the size of the float registers agrees with the ABI and ISA.  */
+  switch (opts->fp)
+    {
+    case 0:
+      if (!CPU_HAS_LDC1_SDC1 (opts->arch))
+       as_bad (_("`fp=xx' used with a cpu lacking ldc1/sdc1 instructions"));
+      else if (opts->single_float == 1)
+       as_bad (_("`fp=xx' cannot be used with `singlefloat'"));
+      break;
+    case 64:
+      if (!ISA_HAS_64BIT_FPRS (opts->isa))
+       as_bad (_("`fp=64' used with a 32-bit fpu"));
+      else if (abi_checks
+              && ABI_NEEDS_32BIT_REGS (mips_abi)
+              && !ISA_HAS_MXHC1 (opts->isa))
+       as_warn (_("`fp=64' used with a 32-bit ABI"));
+      break;
+    case 32:
+      if (abi_checks
+         && ABI_NEEDS_64BIT_REGS (mips_abi))
+       as_warn (_("`fp=32' used with a 64-bit ABI"));
+      if (ISA_IS_R6 (mips_opts.isa) && opts->single_float == 0)
+       as_bad (_("`fp=32' used with a MIPS R6 cpu"));
+      break;
+    default:
+      as_bad (_("Unknown size of floating point registers"));
+      break;
+    }
+
+  if (ABI_NEEDS_64BIT_REGS (mips_abi) && !opts->oddspreg)
+    as_bad (_("`nooddspreg` cannot be used with a 64-bit ABI"));
+
+  if (opts->micromips == 1 && opts->mips16 == 1)
+    as_bad (_("`mips16' cannot be used with `micromips'"));
+  else if (ISA_IS_R6 (mips_opts.isa)
+          && (opts->micromips == 1
+              || opts->mips16 == 1))
+    as_fatal (_("`%s' can not be used with `%s'"),
+             opts->micromips ? "micromips" : "mips16",
+             mips_cpu_info_from_isa (mips_opts.isa)->name);
+
+  if (ISA_IS_R6 (opts->isa) && mips_relax_branch)
+    as_fatal (_("branch relaxation is not supported in `%s'"),
+             mips_cpu_info_from_isa (opts->isa)->name);
+}
+
+/* Perform consistency checks on the module level options exactly once.
+   This is a deferred check that happens:
+     at the first .set directive
+     or, at the first pseudo op that generates code (inc .dc.a)
+     or, at the first instruction
+     or, at the end.  */
+
+static void
+file_mips_check_options (void)
+{
+  const struct mips_cpu_info *arch_info = 0;
+
+  if (file_mips_opts_checked)
+    return;
+
+  /* The following code determines the register size.
+     Similar code was added to GCC 3.3 (see override_options() in
+     config/mips/mips.c).  The GAS and GCC code should be kept in sync
+     as much as possible.  */
+
+  if (file_mips_opts.gp < 0)
+    {
+      /* Infer the integer register size from the ABI and processor.
+        Restrict ourselves to 32-bit registers if that's all the
+        processor has, or if the ABI cannot handle 64-bit registers.  */
+      file_mips_opts.gp = (ABI_NEEDS_32BIT_REGS (mips_abi)
+                          || !ISA_HAS_64BIT_REGS (file_mips_opts.isa))
+                         ? 32 : 64;
+    }
+
+  if (file_mips_opts.fp < 0)
+    {
+      /* No user specified float register size.
+        ??? GAS treats single-float processors as though they had 64-bit
+        float registers (although it complains when double-precision
+        instructions are used).  As things stand, saying they have 32-bit
+        registers would lead to spurious "register must be even" messages.
+        So here we assume float registers are never smaller than the
+        integer ones.  */
+      if (file_mips_opts.gp == 64)
+       /* 64-bit integer registers implies 64-bit float registers.  */
+       file_mips_opts.fp = 64;
+      else if ((file_mips_opts.ase & FP64_ASES)
+              && ISA_HAS_64BIT_FPRS (file_mips_opts.isa))
+       /* Handle ASEs that require 64-bit float registers, if possible.  */
+       file_mips_opts.fp = 64;
+      else if (ISA_IS_R6 (mips_opts.isa))
+       /* R6 implies 64-bit float registers.  */
+       file_mips_opts.fp = 64;
+      else
+       /* 32-bit float registers.  */
+       file_mips_opts.fp = 32;
+    }
+
+  arch_info = mips_cpu_info_from_arch (file_mips_opts.arch);
+
+  /* Disable operations on odd-numbered floating-point registers by default
+     when using the FPXX ABI.  */
+  if (file_mips_opts.oddspreg < 0)
+    {
+      if (file_mips_opts.fp == 0)
+       file_mips_opts.oddspreg = 0;
+      else
+       file_mips_opts.oddspreg = 1;
+    }
+
+  /* End of GCC-shared inference code.  */
+
+  /* This flag is set when we have a 64-bit capable CPU but use only
+     32-bit wide registers.  Note that EABI does not use it.  */
+  if (ISA_HAS_64BIT_REGS (file_mips_opts.isa)
+      && ((mips_abi == NO_ABI && file_mips_opts.gp == 32)
+         || mips_abi == O32_ABI))
+    mips_32bitmode = 1;
+
+  if (file_mips_opts.isa == ISA_MIPS1 && mips_trap)
+    as_bad (_("trap exception not supported at ISA 1"));
+
+  /* If the selected architecture includes support for ASEs, enable
+     generation of code for them.  */
+  if (file_mips_opts.mips16 == -1)
+    file_mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_opts.arch)) ? 1 : 0;
+  if (file_mips_opts.micromips == -1)
+    file_mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_opts.arch))
+                               ? 1 : 0;
+
+  if (mips_nan2008 == -1)
+    mips_nan2008 = (ISA_HAS_LEGACY_NAN (file_mips_opts.isa)) ? 0 : 1;
+  else if (!ISA_HAS_LEGACY_NAN (file_mips_opts.isa) && mips_nan2008 == 0)
+    as_fatal (_("`%s' does not support legacy NaN"),
+             mips_cpu_info_from_arch (file_mips_opts.arch)->name);
+
+  /* Some ASEs require 64-bit FPRs, so -mfp32 should stop those ASEs from
+     being selected implicitly.  */
+  if (file_mips_opts.fp != 64)
+    file_ase_explicit |= ASE_MIPS3D | ASE_MDMX | ASE_MSA;
+
+  /* If the user didn't explicitly select or deselect a particular ASE,
+     use the default setting for the CPU.  */
+  file_mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
+
+  /* Set up the current options.  These may change throughout assembly.  */
+  mips_opts = file_mips_opts;
+
+  mips_check_isa_supports_ases ();
+  mips_check_options (&file_mips_opts, TRUE);
+  file_mips_opts_checked = TRUE;
+
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_opts.arch))
+    as_warn (_("could not set architecture and machine"));
 }
 
 void
@@ -3653,6 +3983,8 @@ md_assemble (char *str)
   bfd_reloc_code_real_type unused_reloc[3]
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
+  file_mips_check_options ();
+
   imm_expr.X_op = O_absent;
   offset_expr.X_op = O_absent;
   offset_reloc[0] = BFD_RELOC_UNUSED;
@@ -3803,9 +4135,15 @@ limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
     case BFD_RELOC_MICROMIPS_10_PCREL_S1:
     case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+    case BFD_RELOC_MIPS_21_PCREL_S2:
+    case BFD_RELOC_MIPS_26_PCREL_S2:
+    case BFD_RELOC_MIPS_18_PCREL_S3:
+    case BFD_RELOC_MIPS_19_PCREL_S2:
       return TRUE;
 
     case BFD_RELOC_32_PCREL:
+    case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_LO16_PCREL:
       return HAVE_64BIT_ADDRESSES;
 
     default:
@@ -4108,6 +4446,20 @@ operand_reg_mask (const struct mips_cl_insn *insn,
       uval = insn_extract_operand (insn, operand);
       return (1 << (uval & 31)) | (1 << (uval >> 5));
 
+    case OP_SAME_RS_RT:
+      if (!(type_mask & (1 << OP_REG_GP)))
+       return 0;
+      uval = insn_extract_operand (insn, operand);
+      gas_assert ((uval & 31) == (uval >> 5));
+      return 1 << (uval & 31);
+
+    case OP_CHECK_PREV:
+    case OP_NON_ZERO_REG:
+      if (!(type_mask & (1 << OP_REG_GP)))
+       return 0;
+      uval = insn_extract_operand (insn, operand);
+      return 1 << (uval & 31);
+
     case OP_LWM_SWM_LIST:
       abort ();
 
@@ -4222,7 +4574,7 @@ fpr_read_mask (const struct mips_cl_insn *ip)
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
      (This is overly pessimistic for things like cvt.d.s.)  */
-  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+  if (FPR_SIZE != 64 && (pinfo & FP_D))
     mask |= mask << 1;
   return mask;
 }
@@ -4241,7 +4593,7 @@ fpr_write_mask (const struct mips_cl_insn *ip)
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
      (This is overly pessimistic for things like cvt.s.d.)  */
-  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
+  if (FPR_SIZE != 64 && (pinfo & FP_D))
     mask |= mask << 1;
   return mask;
 }
@@ -4253,39 +4605,42 @@ static bfd_boolean
 mips_oddfpreg_ok (const struct mips_opcode *insn, int opnum)
 {
   const char *s = insn->name;
+  bfd_boolean oddspreg = (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa, mips_opts.arch)
+                         || FPR_SIZE == 64)
+                        && mips_opts.oddspreg;
 
   if (insn->pinfo == INSN_MACRO)
     /* Let a macro pass, we'll catch it later when it is expanded.  */
     return TRUE;
 
-  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa) || mips_opts.arch == CPU_R5900)
-    {
-      /* Allow odd registers for single-precision ops.  */
-      switch (insn->pinfo & (FP_S | FP_D))
-       {
-       case FP_S:
-       case 0:
-         return TRUE;
-       case FP_D:
-         return FALSE;
-       default:
-         break;
-       }
+  /* Single-precision coprocessor loads and moves are OK for 32-bit registers,
+     otherwise it depends on oddspreg.  */
+  if ((insn->pinfo & FP_S)
+      && (insn->pinfo & (INSN_LOAD_MEMORY | INSN_STORE_MEMORY
+                        | INSN_LOAD_COPROC | INSN_COPROC_MOVE)))
+    return FPR_SIZE == 32 || oddspreg;
 
-      /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand.  */
-      s = strchr (insn->name, '.');
-      if (s != NULL && opnum == 2)
-       s = strchr (s + 1, '.');
-      return (s != NULL && (s[1] == 'w' || s[1] == 's'));
+  /* Allow odd registers for single-precision ops and double-precision if the
+     floating-point registers are 64-bit wide.  */
+  switch (insn->pinfo & (FP_S | FP_D))
+    {
+    case FP_S:
+    case 0:
+      return oddspreg;
+    case FP_D:
+      return FPR_SIZE == 64;
+    default:
+      break;
     }
 
-  /* Single-precision coprocessor loads and moves are OK too.  */
-  if ((insn->pinfo & FP_S)
-      && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY
-                        | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY)))
-    return TRUE;
+  /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand.  */
+  s = strchr (insn->name, '.');
+  if (s != NULL && opnum == 2)
+    s = strchr (s + 1, '.');
+  if (s != NULL && (s[1] == 'w' || s[1] == 's'))
+    return oddspreg;
 
-  return FALSE;
+  return FPR_SIZE == 64;
 }
 
 /* Information about an instruction argument that we're trying to match.  */
@@ -4441,9 +4796,9 @@ convert_reg_type (const struct mips_opcode *opcode,
         FPR load, store or move (including moves to and from GPRs).  */
       if ((mips_opts.ase & ASE_MDMX)
          && (opcode->pinfo & FP_D)
-         && (opcode->pinfo & (INSN_COPROC_MOVE_DELAY
+         && (opcode->pinfo & (INSN_COPROC_MOVE
                               | INSN_COPROC_MEMORY_DELAY
-                              | INSN_LOAD_COPROC_DELAY
+                              | INSN_LOAD_COPROC
                               | INSN_LOAD_MEMORY
                               | INSN_STORE_MEMORY)))
        return RTYPE_FPU | RTYPE_VEC;
@@ -4508,9 +4863,16 @@ check_regno (struct mips_arg_info *arg,
 
   if (type == OP_REG_FP
       && (regno & 1) != 0
-      && HAVE_32BIT_FPRS
       && !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum))
-    as_warn (_("float register should be even, was %d"), regno);
+    {
+      /* This was a warning prior to introducing O32 FPXX and FP64 support
+        so maintain a warning for FP32 but raise an error for the new
+        cases.  */
+      if (FPR_SIZE == 32)
+       as_warn (_("float register should be even, was %d"), regno);
+      else
+       as_bad (_("float register should be even, was %d"), regno);
+    }
 
   if (type == OP_REG_CCC)
     {
@@ -4890,6 +5252,58 @@ match_clo_clz_dest_operand (struct mips_arg_info *arg,
   return TRUE;
 }
 
+/* OP_CHECK_PREV matcher.  */
+
+static bfd_boolean
+match_check_prev_operand (struct mips_arg_info *arg,
+                         const struct mips_operand *operand_base)
+{
+  const struct mips_check_prev_operand *operand;
+  unsigned int regno;
+
+  operand = (const struct mips_check_prev_operand *) operand_base;
+
+  if (!match_reg (arg, OP_REG_GP, &regno))
+    return FALSE;
+
+  if (!operand->zero_ok && regno == 0)
+    return FALSE;
+
+  if ((operand->less_than_ok && regno < arg->last_regno)
+      || (operand->greater_than_ok && regno > arg->last_regno)
+      || (operand->equal_ok && regno == arg->last_regno))
+    {
+      arg->last_regno = regno;
+      insn_insert_operand (arg->insn, operand_base, regno);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* OP_SAME_RS_RT matcher.  */
+
+static bfd_boolean
+match_same_rs_rt_operand (struct mips_arg_info *arg,
+                         const struct mips_operand *operand)
+{
+  unsigned int regno;
+
+  if (!match_reg (arg, OP_REG_GP, &regno))
+    return FALSE;
+
+  if (regno == 0)
+    {
+      set_insn_error (arg->argnum, _("the source register must not be $0"));
+      return FALSE;
+    }
+
+  arg->last_regno = regno;
+
+  insn_insert_operand (arg->insn, operand, regno | (regno << 5));
+  return TRUE;
+}
+
 /* OP_LWM_SWM_LIST matcher.  */
 
 static bfd_boolean
@@ -5283,6 +5697,25 @@ match_pc_operand (struct mips_arg_info *arg)
   return FALSE;
 }
 
+/* OP_NON_ZERO_REG matcher.  */
+
+static bfd_boolean
+match_non_zero_reg_operand (struct mips_arg_info *arg,
+                           const struct mips_operand *operand)
+{
+  unsigned int regno;
+
+  if (!match_reg (arg, OP_REG_GP, &regno))
+    return FALSE;
+
+  if (regno == 0)
+    return FALSE;
+
+  arg->last_regno = regno;
+  insn_insert_operand (arg->insn, operand, regno);
+  return TRUE;
+}
+
 /* OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG matcher.  OTHER_REGNO is the
    register that we need to match.  */
 
@@ -5364,13 +5797,16 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
   /* Handle 64-bit constants for which an immediate value is best.  */
   if (length == 8
       && !mips_disable_float_construction
-      /* Constants can only be constructed in GPRs and copied
-        to FPRs if the GPRs are at least as wide as the FPRs.
-        Force the constant into memory if we are using 64-bit FPRs
-        but the GPRs are only 32 bits wide.  */
-      /* ??? No longer true with the addition of MTHC1, but this
-        is legacy code...  */
-      && (using_gprs || !(HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
+      /* Constants can only be constructed in GPRs and copied to FPRs if the
+        GPRs are at least as wide as the FPRs or MTHC1 is available.
+        Unlike most tests for 32-bit floating-point registers this check
+        specifically looks for GPR_SIZE == 32 as the FPXX ABI does not
+        permit 64-bit moves without MXHC1.
+        Force the constant into memory otherwise.  */
+      && (using_gprs
+         || GPR_SIZE == 64
+         || ISA_HAS_MXHC1 (mips_opts.isa)
+         || FPR_SIZE == 32)
       && ((data[0] == 0 && data[1] == 0)
          || (data[2] == 0 && data[3] == 0))
       && ((data[4] == 0 && data[5] == 0)
@@ -5380,7 +5816,7 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm,
         If using 32-bit registers, set IMM to the high order 32 bits and
         OFFSET to the low order 32 bits.  Otherwise, set IMM to the entire
         64 bit constant.  */
-      if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
+      if (GPR_SIZE == 32 || (!using_gprs && FPR_SIZE != 64))
        {
          imm->X_op = O_constant;
          offset->X_op = O_constant;
@@ -5556,6 +5992,15 @@ match_operand (struct mips_arg_info *arg,
 
     case OP_REG_INDEX:
       return match_reg_index_operand (arg, operand);
+
+    case OP_SAME_RS_RT:
+      return match_same_rs_rt_operand (arg, operand);
+
+    case OP_CHECK_PREV:
+      return match_check_prev_operand (arg, operand);
+
+    case OP_NON_ZERO_REG:
+      return match_non_zero_reg_operand (arg, operand);
     }
   abort ();
 }
@@ -5585,7 +6030,7 @@ reg_needs_delay (unsigned int reg)
   prev_pinfo = history[0].insn_mo->pinfo;
   if (!mips_opts.noreorder
       && (((prev_pinfo & INSN_LOAD_MEMORY) && !gpr_interlocks)
-         || ((prev_pinfo & INSN_LOAD_COPROC_DELAY) && !cop_interlocks))
+         || ((prev_pinfo & INSN_LOAD_COPROC) && !cop_interlocks))
       && (gpr_write_mask (&history[0]) & (1 << reg)))
     return TRUE;
 
@@ -5703,7 +6148,7 @@ insns_between (const struct mips_cl_insn *insn1,
         are on the RT register.  */
       /* Itbl support may require additional care here.  */
       if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY))
-         || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
+         || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC)))
        {
          if (insn2 == NULL || (gpr_read_mask (insn2) & gpr_write_mask (insn1)))
            return 1;
@@ -5717,7 +6162,7 @@ insns_between (const struct mips_cl_insn *insn1,
       /* Itbl support may require additional care here. FIXME!
         Need to modify this to include knowledge about
         user specified delays!  */
-      else if ((!cop_interlocks && (pinfo1 & INSN_COPROC_MOVE_DELAY))
+      else if ((!cop_interlocks && (pinfo1 & INSN_COPROC_MOVE))
               || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
        {
          /* Handle cases where INSN1 writes to a known general coprocessor
@@ -5756,6 +6201,14 @@ insns_between (const struct mips_cl_insn *insn1,
        return 1;
     }
 
+  /* Forbidden slots can not contain Control Transfer Instructions (CTIs)
+     CTIs include all branches and jumps, nal, eret, eretnc, deret, wait
+     and pause.  */
+  if ((insn1->insn_mo->pinfo2 & INSN2_FORBIDDEN_SLOT)
+      && ((pinfo2 & INSN_NO_DELAY_SLOT)
+         || (insn2 && delayed_branch_p (insn2))))
+    return 1;
+
   return 0;
 }
 
@@ -6613,6 +7066,40 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
          }
          break;
 
+       case BFD_RELOC_MIPS_21_PCREL_S2:
+         {
+           int shift;
+
+           shift = 2;
+           if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+             as_bad (_("branch to misaligned address (0x%lx)"),
+                     (unsigned long) address_expr->X_add_number);
+           if ((address_expr->X_add_number + (1 << (shift + 20)))
+               & ~((1 << (shift + 21)) - 1))
+             as_bad (_("branch address range overflow (0x%lx)"),
+                     (unsigned long) address_expr->X_add_number);
+           ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+                               & 0x1fffff);
+         }
+         break;
+
+       case BFD_RELOC_MIPS_26_PCREL_S2:
+         {
+           int shift;
+
+           shift = 2;
+           if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
+             as_bad (_("branch to misaligned address (0x%lx)"),
+                     (unsigned long) address_expr->X_add_number);
+           if ((address_expr->X_add_number + (1 << (shift + 25)))
+               & ~((1 << (shift + 26)) - 1))
+             as_bad (_("branch address range overflow (0x%lx)"),
+                     (unsigned long) address_expr->X_add_number);
+           ip->insn_opcode |= ((address_expr->X_add_number >> shift)
+                               & 0x3ffffff);
+         }
+         break;
+
        default:
          {
            offsetT value;
@@ -6876,7 +7363,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
 
       /* These relocations can have an addend that won't fit in
         4 octets for 64bit assembly.  */
-      if (HAVE_64BIT_GPRS
+      if (GPR_SIZE == 64
          && ! howto->partial_inplace
          && (reloc_type[0] == BFD_RELOC_16
              || reloc_type[0] == BFD_RELOC_32
@@ -7277,12 +7764,33 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
       arg.opnum += 1;
       switch (*args)
        {
+       case '-':
+         switch (args[1])
+           {
+           case 'A':
+             *offset_reloc = BFD_RELOC_MIPS_19_PCREL_S2;
+             break;
+
+           case 'B':
+             *offset_reloc = BFD_RELOC_MIPS_18_PCREL_S3;
+             break;
+           }
+         break;
+
        case '+':
          switch (args[1])
            {
            case 'i':
              *offset_reloc = BFD_RELOC_MIPS_JMP;
              break;
+
+           case '\'':
+             *offset_reloc = BFD_RELOC_MIPS_26_PCREL_S2;
+             break;
+
+           case '\"':
+             *offset_reloc = BFD_RELOC_MIPS_21_PCREL_S2;
+             break;
            }
          break;
 
@@ -7290,7 +7798,7 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
          if (!match_const_int (&arg, &imm_expr.X_add_number))
            return FALSE;
          imm_expr.X_op = O_constant;
-         if (HAVE_32BIT_GPRS)
+         if (GPR_SIZE == 32)
            normalize_constant_expr (&imm_expr);
          continue;
 
@@ -7368,7 +7876,7 @@ match_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
        abort ();
 
       /* Skip prefixes.  */
-      if (*args == '+' || *args == 'm')
+      if (*args == '+' || *args == 'm' || *args == '-')
        args++;
 
       if (mips_optional_operand_p (operand)
@@ -7500,7 +8008,7 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode,
          if (!match_const_int (&arg, &imm_expr.X_add_number))
            return FALSE;
          imm_expr.X_op = O_constant;
-         if (HAVE_32BIT_GPRS)
+         if (GPR_SIZE == 32)
            normalize_constant_expr (&imm_expr);
          continue;
 
@@ -7838,10 +8346,13 @@ 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][mips_opts.insn32])
-#define COP12_FMT (cop12_fmt[mips_opts.micromips])
+#define COP12_FMT (ISA_IS_R6 (mips_opts.isa) ? "E,+:(d)" \
+                                            : 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 LL_SC_FMT (ISA_IS_R6 (mips_opts.isa) ? "t,+j(b)" \
+                                            : mem12_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])
@@ -8019,7 +8530,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
            uval |= (uval << 5);
          insn_insert_operand (&insn, operand, uval);
 
-         if (*fmt == '+' || *fmt == 'm')
+         if (*fmt == '+' || *fmt == 'm' || *fmt == '-')
            ++fmt;
          break;
        }
@@ -8227,7 +8738,7 @@ set_at (int reg, int unsignedp)
                 AT, reg, BFD_RELOC_LO16);
   else
     {
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, unsignedp ? "sltu" : "slt", "d,v,t", AT, reg, AT);
     }
 }
@@ -8353,7 +8864,7 @@ load_register (int reg, expressionS *ep, int dbl)
 
   /* The value is larger than 32 bits.  */
 
-  if (!dbl || HAVE_32BIT_GPRS)
+  if (!dbl || GPR_SIZE == 32)
     {
       char value[32];
 
@@ -8809,7 +9320,7 @@ move_register (int dest, int source)
       && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
     macro_build (NULL, "move", "mp,mj", dest, source);
   else
-    macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
+    macro_build (NULL, GPR_SIZE == 32 ? "addu" : "daddu", "d,v,t",
                 dest, source, 0);
 }
 
@@ -9292,7 +9803,7 @@ macro (struct mips_cl_insn *ip, char *str)
        }
 
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, s2, "d,v,t", op[0], op[1], AT);
       break;
 
@@ -9336,7 +9847,7 @@ macro (struct mips_cl_insn *ip, char *str)
        {
          op[1] = AT;
          used_at = 1;
-         load_register (op[1], &imm_expr, HAVE_64BIT_GPRS);
+         load_register (op[1], &imm_expr, GPR_SIZE == 64);
        }
       /* Fall through.  */
     case M_BEQL:
@@ -9436,7 +9947,7 @@ macro (struct mips_cl_insn *ip, char *str)
       likely = 1;
     case M_BGTU_I:
       if (op[0] == 0
-         || (HAVE_32BIT_GPRS
+         || (GPR_SIZE == 32
              && imm_expr.X_add_number == -1))
        goto do_false;
       ++imm_expr.X_add_number;
@@ -9553,7 +10064,7 @@ macro (struct mips_cl_insn *ip, char *str)
       likely = 1;
     case M_BLEU_I:
       if (op[0] == 0
-         || (HAVE_32BIT_GPRS
+         || (GPR_SIZE == 32
              && imm_expr.X_add_number == -1))
        goto do_true;
       ++imm_expr.X_add_number;
@@ -9818,7 +10329,7 @@ macro (struct mips_cl_insn *ip, char *str)
         zero, we then add a base register to it.  */
 
       breg = op[2];
-      if (dbl && HAVE_32BIT_GPRS)
+      if (dbl && GPR_SIZE == 32)
        as_warn (_("dla used to load 32-bit register"));
 
       if (!dbl && HAVE_64BIT_OBJECTS)
@@ -10788,7 +11299,9 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_LWC2_AB:
       s = "lwc2";
       fmt = COP12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 11
+                : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -10818,7 +11331,9 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_LDC2_AB:
       s = "ldc2";
       fmt = COP12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 11
+                : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -10846,13 +11361,17 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_LL_AB:
       s = "ll";
-      fmt = MEM12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = LL_SC_FMT;
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld;
     case M_LLD_AB:
       s = "lld";
-      fmt = MEM12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = LL_SC_FMT;
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld;
     case M_LWU_AB:
       s = "lwu";
@@ -10922,7 +11441,9 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_SWC2_AB:
       s = "swc2";
       fmt = COP12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 11
+                : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -10945,18 +11466,26 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_SC_AB:
       s = "sc";
-      fmt = MEM12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = LL_SC_FMT;
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld_st;
     case M_SCD_AB:
       s = "scd";
-      fmt = MEM12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = LL_SC_FMT;
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld_st;
     case M_CACHE_AB:
       s = "cache";
-      fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = (mips_opts.micromips ? "k,~(b)"
+            : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+            : "k,o(b)");
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld_st;
     case M_CACHEE_AB:
       s = "cachee";
@@ -10965,8 +11494,12 @@ macro (struct mips_cl_insn *ip, char *str)
       goto ld_st;
     case M_PREF_AB:
       s = "pref";
-      fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
-      offbits = (mips_opts.micromips ? 12 : 16);
+      fmt = (mips_opts.micromips ? "k,~(b)"
+            : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+            : "k,o(b)");
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 9
+                : 16);
       goto ld_st;
     case M_PREFE_AB:
       s = "prefe";
@@ -10982,7 +11515,9 @@ macro (struct mips_cl_insn *ip, char *str)
     case M_SDC2_AB:
       s = "sdc2";
       fmt = COP12_FMT;
-      offbits = (mips_opts.micromips ? 12 : 16);
+      offbits = (mips_opts.micromips ? 12
+                : ISA_IS_R6 (mips_opts.isa) ? 11
+                : 16);
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
@@ -11481,7 +12016,7 @@ macro (struct mips_cl_insn *ip, char *str)
          zero or in OFFSET_EXPR.  */
       if (imm_expr.X_op == O_constant)
        {
-         if (HAVE_64BIT_GPRS)
+         if (GPR_SIZE == 64)
            load_register (op[0], &imm_expr, 1);
          else
            {
@@ -11530,7 +12065,7 @@ macro (struct mips_cl_insn *ip, char *str)
        }
 
       /* Now we load the register(s).  */
-      if (HAVE_64BIT_GPRS)
+      if (GPR_SIZE == 64)
        {
          used_at = 1;
          macro_build (&offset_expr, "ld", "t,o(b)", op[0],
@@ -11561,15 +12096,19 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm_expr.X_op == O_constant)
        {
          used_at = 1;
-         load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
-         if (HAVE_64BIT_FPRS)
-           {
-             gas_assert (HAVE_64BIT_GPRS);
-             macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
-           }
+         load_register (AT, &imm_expr, FPR_SIZE == 64);
+         if (FPR_SIZE == 64 && GPR_SIZE == 64)
+           macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
          else
            {
-             macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
+             if (ISA_HAS_MXHC1 (mips_opts.isa))
+               macro_build (NULL, "mthc1", "t,G", AT, op[0]);
+             else if (FPR_SIZE != 32)
+               as_bad (_("Unable to generate `%s' compliant code "
+                         "without mthc1"),
+                       (FPR_SIZE == 64) ? "fp64" : "fpxx");
+             else
+               macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1);
              if (offset_expr.X_op == O_absent)
                macro_build (NULL, "mtc1", "t,G", 0, op[0]);
              else
@@ -11662,7 +12201,7 @@ macro (struct mips_cl_insn *ip, char *str)
 
     case M_LD_AB:
       fmt = "t,o(b)";
-      if (HAVE_64BIT_GPRS)
+      if (GPR_SIZE == 64)
        {
          s = "ld";
          goto ld;
@@ -11672,7 +12211,7 @@ macro (struct mips_cl_insn *ip, char *str)
 
     case M_SD_AB:
       fmt = "t,o(b)";
-      if (HAVE_64BIT_GPRS)
+      if (GPR_SIZE == 64)
        {
          s = "sd";
          goto ld_st;
@@ -11945,11 +12484,11 @@ macro (struct mips_cl_insn *ip, char *str)
        
     case M_SAA_AB:
       s = "saa";
-      offbits = 0;
-      fmt = "t,(b)";
-      goto ld_st;
+      goto saa_saad;
     case M_SAAD_AB:
       s = "saad";
+    saa_saad:
+      gas_assert (!mips_opts.micromips);
       offbits = 0;
       fmt = "t,(b)";
       goto ld_st;
@@ -12313,19 +12852,19 @@ macro (struct mips_cl_insn *ip, char *str)
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
+         macro_build (&imm_expr, GPR_SIZE == 32 ? "addiu" : "daddiu",
                       "t,r,j", op[0], op[1], BFD_RELOC_LO16);
        }
       else if (CPU_HAS_SEQ (mips_opts.arch))
        {
          used_at = 1;
-         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (AT, &imm_expr, GPR_SIZE == 64);
          macro_build (NULL, "seq", "d,v,t", op[0], op[1], AT);
          break;
        }
       else
        {
-         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (AT, &imm_expr, GPR_SIZE == 64);
          macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
          used_at = 1;
        }
@@ -12350,7 +12889,7 @@ macro (struct mips_cl_insn *ip, char *str)
                     op[0], op[1], BFD_RELOC_LO16);
       else
        {
-         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (AT, &imm_expr, GPR_SIZE == 64);
          macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
                       op[0], op[1], AT);
          used_at = 1;
@@ -12374,7 +12913,7 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "sltu";
     sgti:
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       break;
 
@@ -12395,7 +12934,7 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "sltu";
     slei:
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
@@ -12409,7 +12948,7 @@ macro (struct mips_cl_insn *ip, char *str)
          break;
        }
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, "slt", "d,v,t", op[0], op[1], AT);
       break;
 
@@ -12422,7 +12961,7 @@ macro (struct mips_cl_insn *ip, char *str)
          break;
        }
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, "sltu", "d,v,t", op[0], op[1], AT);
       break;
 
@@ -12448,7 +12987,7 @@ macro (struct mips_cl_insn *ip, char *str)
        {
          as_warn (_("instruction %s: result is always true"),
                   ip->insn_mo->name);
-         macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
+         macro_build (&expr1, GPR_SIZE == 32 ? "addiu" : "daddiu", "t,r,j",
                       op[0], 0, BFD_RELOC_LO16);
          break;
        }
@@ -12470,19 +13009,19 @@ macro (struct mips_cl_insn *ip, char *str)
               && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
-         macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
+         macro_build (&imm_expr, GPR_SIZE == 32 ? "addiu" : "daddiu",
                       "t,r,j", op[0], op[1], BFD_RELOC_LO16);
        }
       else if (CPU_HAS_SEQ (mips_opts.arch))
        {
          used_at = 1;
-         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (AT, &imm_expr, GPR_SIZE == 64);
          macro_build (NULL, "sne", "d,v,t", op[0], op[1], AT);
          break;
        }
       else
        {
-         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         load_register (AT, &imm_expr, GPR_SIZE == 64);
          macro_build (NULL, "xor", "d,v,t", op[0], op[1], AT);
          used_at = 1;
        }
@@ -12548,7 +13087,7 @@ macro (struct mips_cl_insn *ip, char *str)
       s = "tne";
     trap:
       used_at = 1;
-      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+      load_register (AT, &imm_expr, GPR_SIZE == 64);
       macro_build (NULL, s, "s,t", op[0], AT);
       break;
 
@@ -13305,7 +13844,9 @@ 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},
-  {"%hi", BFD_RELOC_HI16_S}
+  {"%hi", BFD_RELOC_HI16_S},
+  {"%pcrel_hi", BFD_RELOC_HI16_S_PCREL},
+  {"%pcrel_lo", BFD_RELOC_LO16_PCREL}
 };
 
 static const struct percent_op_match mips16_percent_op[] =
@@ -13498,7 +14039,7 @@ md_parse_option (int c, char *arg)
   for (i = 0; i < ARRAY_SIZE (mips_ases); i++)
     if (c == mips_ases[i].option_on || c == mips_ases[i].option_off)
       {
-       file_ase_explicit |= mips_set_ase (&mips_ases[i],
+       file_ase_explicit |= mips_set_ase (&mips_ases[i], &file_mips_opts,
                                           c == mips_ases[i].option_on);
        return 1;
       }
@@ -13548,55 +14089,63 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_MIPS1:
-      file_mips_isa = ISA_MIPS1;
+      file_mips_opts.isa = ISA_MIPS1;
       break;
 
     case OPTION_MIPS2:
-      file_mips_isa = ISA_MIPS2;
+      file_mips_opts.isa = ISA_MIPS2;
       break;
 
     case OPTION_MIPS3:
-      file_mips_isa = ISA_MIPS3;
+      file_mips_opts.isa = ISA_MIPS3;
       break;
 
     case OPTION_MIPS4:
-      file_mips_isa = ISA_MIPS4;
+      file_mips_opts.isa = ISA_MIPS4;
       break;
 
     case OPTION_MIPS5:
-      file_mips_isa = ISA_MIPS5;
+      file_mips_opts.isa = ISA_MIPS5;
       break;
 
     case OPTION_MIPS32:
-      file_mips_isa = ISA_MIPS32;
+      file_mips_opts.isa = ISA_MIPS32;
       break;
 
     case OPTION_MIPS32R2:
-      file_mips_isa = ISA_MIPS32R2;
+      file_mips_opts.isa = ISA_MIPS32R2;
       break;
 
     case OPTION_MIPS32R3:
-      file_mips_isa = ISA_MIPS32R3;
+      file_mips_opts.isa = ISA_MIPS32R3;
       break;
 
     case OPTION_MIPS32R5:
-      file_mips_isa = ISA_MIPS32R5;
+      file_mips_opts.isa = ISA_MIPS32R5;
+      break;
+
+    case OPTION_MIPS32R6:
+      file_mips_opts.isa = ISA_MIPS32R6;
       break;
 
     case OPTION_MIPS64R2:
-      file_mips_isa = ISA_MIPS64R2;
+      file_mips_opts.isa = ISA_MIPS64R2;
       break;
 
     case OPTION_MIPS64R3:
-      file_mips_isa = ISA_MIPS64R3;
+      file_mips_opts.isa = ISA_MIPS64R3;
       break;
 
     case OPTION_MIPS64R5:
-      file_mips_isa = ISA_MIPS64R5;
+      file_mips_opts.isa = ISA_MIPS64R5;
+      break;
+
+    case OPTION_MIPS64R6:
+      file_mips_opts.isa = ISA_MIPS64R6;
       break;
 
     case OPTION_MIPS64:
-      file_mips_isa = ISA_MIPS64;
+      file_mips_opts.isa = ISA_MIPS64;
       break;
 
     case OPTION_MTUNE:
@@ -13640,32 +14189,32 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_MICROMIPS:
-      if (mips_opts.mips16 == 1)
+      if (file_mips_opts.mips16 == 1)
        {
          as_bad (_("-mmicromips cannot be used with -mips16"));
          return 0;
        }
-      mips_opts.micromips = 1;
+      file_mips_opts.micromips = 1;
       mips_no_prev_insn ();
       break;
 
     case OPTION_NO_MICROMIPS:
-      mips_opts.micromips = 0;
+      file_mips_opts.micromips = 0;
       mips_no_prev_insn ();
       break;
 
     case OPTION_MIPS16:
-      if (mips_opts.micromips == 1)
+      if (file_mips_opts.micromips == 1)
        {
          as_bad (_("-mips16 cannot be used with -micromips"));
          return 0;
        }
-      mips_opts.mips16 = 1;
+      file_mips_opts.mips16 = 1;
       mips_no_prev_insn ();
       break;
 
     case OPTION_NO_MIPS16:
-      mips_opts.mips16 = 0;
+      file_mips_opts.mips16 = 0;
       mips_no_prev_insn ();
       break;
 
@@ -13734,11 +14283,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_INSN32:
-      mips_opts.insn32 = TRUE;
+      file_mips_opts.insn32 = TRUE;
       break;
 
     case OPTION_NO_INSN32:
-      mips_opts.insn32 = FALSE;
+      file_mips_opts.insn32 = FALSE;
       break;
 
     case OPTION_MSHARED:
@@ -13750,11 +14299,11 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_MSYM32:
-      mips_opts.sym32 = TRUE;
+      file_mips_opts.sym32 = TRUE;
       break;
 
     case OPTION_MNO_SYM32:
-      mips_opts.sym32 = FALSE;
+      file_mips_opts.sym32 = FALSE;
       break;
 
       /* When generating ELF code, we permit -KPIC and -call_shared to
@@ -13804,35 +14353,47 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_GP32:
-      file_mips_gp32 = 1;
+      file_mips_opts.gp = 32;
       break;
 
     case OPTION_GP64:
-      file_mips_gp32 = 0;
+      file_mips_opts.gp = 64;
       break;
 
     case OPTION_FP32:
-      file_mips_fp32 = 1;
+      file_mips_opts.fp = 32;
+      break;
+
+    case OPTION_FPXX:
+      file_mips_opts.fp = 0;
       break;
 
     case OPTION_FP64:
-      file_mips_fp32 = 0;
+      file_mips_opts.fp = 64;
+      break;
+
+    case OPTION_ODD_SPREG:
+      file_mips_opts.oddspreg = 1;
+      break;
+
+    case OPTION_NO_ODD_SPREG:
+      file_mips_opts.oddspreg = 0;
       break;
 
     case OPTION_SINGLE_FLOAT:
-      file_mips_single_float = 1;
+      file_mips_opts.single_float = 1;
       break;
 
     case OPTION_DOUBLE_FLOAT:
-      file_mips_single_float = 0;
+      file_mips_opts.single_float = 0;
       break;
 
     case OPTION_SOFT_FLOAT:
-      file_mips_soft_float = 1;
+      file_mips_opts.soft_float = 1;
       break;
 
     case OPTION_HARD_FLOAT:
-      file_mips_soft_float = 0;
+      file_mips_opts.soft_float = 0;
       break;
 
     case OPTION_MABI:
@@ -13888,9 +14449,9 @@ md_parse_option (int c, char *arg)
 
     case OPTION_NAN:
       if (strcmp (arg, "2008") == 0)
-       mips_flag_nan2008 = TRUE;
+       mips_nan2008 = 1;
       else if (strcmp (arg, "legacy") == 0)
-       mips_flag_nan2008 = FALSE;
+       mips_nan2008 = 0;
       else
        {
          as_fatal (_("invalid NaN setting -mnan=%s"), arg);
@@ -13907,22 +14468,7 @@ md_parse_option (int c, char *arg)
   return 1;
 }
 \f
-/* Set up globals to generate code for the ISA or processor
-   described by INFO.  */
-
-static void
-mips_set_architecture (const struct mips_cpu_info *info)
-{
-  if (info != 0)
-    {
-      file_mips_arch = info->cpu;
-      mips_opts.arch = info->cpu;
-      mips_opts.isa = info->isa;
-    }
-}
-
-
-/* Likewise for tuning.  */
+/* Set up globals to tune for the ISA or processor described by INFO.  */
 
 static void
 mips_set_tune (const struct mips_cpu_info *info)
@@ -13949,7 +14495,7 @@ mips_after_parse_args (void)
   if (mips_abi == NO_ABI)
     mips_abi = MIPS_DEFAULT_ABI;
 
-  /* The following code determines the architecture and register size.
+  /* The following code determines the architecture.
      Similar code was added to GCC 3.3 (see override_options() in
      config/mips/mips.c).  The GAS and GCC code should be kept in sync
      as much as possible.  */
@@ -13957,9 +14503,9 @@ mips_after_parse_args (void)
   if (mips_arch_string != 0)
     arch_info = mips_parse_cpu ("-march", mips_arch_string);
 
-  if (file_mips_isa != ISA_UNKNOWN)
+  if (file_mips_opts.isa != ISA_UNKNOWN)
     {
-      /* Handle -mipsN.  At this point, file_mips_isa contains the
+      /* Handle -mipsN.  At this point, file_mips_opts.isa contains the
         ISA level specified by -mipsN, while arch_info->isa contains
         the -march selection (if any).  */
       if (arch_info != 0)
@@ -13967,14 +14513,14 @@ mips_after_parse_args (void)
          /* -march takes precedence over -mipsN, since it is more descriptive.
             There's no harm in specifying both as long as the ISA levels
             are the same.  */
-         if (file_mips_isa != arch_info->isa)
+         if (file_mips_opts.isa != arch_info->isa)
            as_bad (_("-%s conflicts with the other architecture options,"
                      " which imply -%s"),
-                   mips_cpu_info_from_isa (file_mips_isa)->name,
+                   mips_cpu_info_from_isa (file_mips_opts.isa)->name,
                    mips_cpu_info_from_isa (arch_info->isa)->name);
        }
       else
-       arch_info = mips_cpu_info_from_isa (file_mips_isa);
+       arch_info = mips_cpu_info_from_isa (file_mips_opts.isa);
     }
 
   if (arch_info == 0)
@@ -13987,9 +14533,17 @@ mips_after_parse_args (void)
     as_bad (_("-march=%s is not compatible with the selected ABI"),
            arch_info->name);
 
-  mips_set_architecture (arch_info);
+  file_mips_opts.arch = arch_info->cpu;
+  file_mips_opts.isa = arch_info->isa;
+
+  /* Set up initial mips_opts state.  */
+  mips_opts = file_mips_opts;
+
+  /* The register size inference code is now placed in
+     file_mips_check_options.  */
 
-  /* Optimize for file_mips_arch, unless -mtune selects a different processor.  */
+  /* Optimize for file_mips_opts.arch, unless -mtune selects a different
+     processor.  */
   if (mips_tune_string != 0)
     tune_info = mips_parse_cpu ("-mtune", mips_tune_string);
 
@@ -13998,101 +14552,6 @@ mips_after_parse_args (void)
   else
     mips_set_tune (tune_info);
 
-  if (file_mips_gp32 >= 0)
-    {
-      /* The user specified the size of the integer registers.  Make sure
-        it agrees with the ABI and ISA.  */
-      if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_bad (_("-mgp64 used with a 32-bit processor"));
-      else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
-       as_bad (_("-mgp32 used with a 64-bit ABI"));
-      else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
-       as_bad (_("-mgp64 used with a 32-bit ABI"));
-    }
-  else
-    {
-      /* Infer the integer register size from the ABI and processor.
-        Restrict ourselves to 32-bit registers if that's all the
-        processor has, or if the ABI cannot handle 64-bit registers.  */
-      file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
-                       || !ISA_HAS_64BIT_REGS (mips_opts.isa));
-    }
-
-  switch (file_mips_fp32)
-    {
-    default:
-    case -1:
-      /* No user specified float register size.
-        ??? GAS treats single-float processors as though they had 64-bit
-        float registers (although it complains when double-precision
-        instructions are used).  As things stand, saying they have 32-bit
-        registers would lead to spurious "register must be even" messages.
-        So here we assume float registers are never smaller than the
-        integer ones.  */
-      if (file_mips_gp32 == 0)
-       /* 64-bit integer registers implies 64-bit float registers.  */
-       file_mips_fp32 = 0;
-      else if ((mips_opts.ase & FP64_ASES)
-              && ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       /* -mips3d and -mdmx imply 64-bit float registers, if possible.  */
-       file_mips_fp32 = 0;
-      else
-       /* 32-bit float registers.  */
-       file_mips_fp32 = 1;
-      break;
-
-    /* The user specified the size of the float registers.  Check if it
-       agrees with the ABI and ISA.  */
-    case 0:
-      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_bad (_("-mfp64 used with a 32-bit fpu"));
-      else if (ABI_NEEDS_32BIT_REGS (mips_abi)
-              && !ISA_HAS_MXHC1 (mips_opts.isa))
-       as_warn (_("-mfp64 used with a 32-bit ABI"));
-      break;
-    case 1:
-      if (ABI_NEEDS_64BIT_REGS (mips_abi))
-       as_warn (_("-mfp32 used with a 64-bit ABI"));
-      break;
-    }
-
-  /* End of GCC-shared inference code.  */
-
-  /* This flag is set when we have a 64-bit capable CPU but use only
-     32-bit wide registers.  Note that EABI does not use it.  */
-  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
-      && ((mips_abi == NO_ABI && file_mips_gp32 == 1)
-         || mips_abi == O32_ABI))
-    mips_32bitmode = 1;
-
-  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
-    as_bad (_("trap exception not supported at ISA 1"));
-
-  /* If the selected architecture includes support for ASEs, enable
-     generation of code for them.  */
-  if (mips_opts.mips16 == -1)
-    mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
-  if (mips_opts.micromips == -1)
-    mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_arch)) ? 1 : 0;
-
-  /* MIPS3D and MDMX require 64-bit FPRs, so -mfp32 should stop those
-     ASEs from being selected implicitly.  */
-  if (file_mips_fp32 == 1)
-    file_ase_explicit |= ASE_MIPS3D | ASE_MDMX;
-
-  /* If the user didn't explicitly select or deselect a particular ASE,
-     use the default setting for the CPU.  */
-  mips_opts.ase |= (arch_info->ase & ~file_ase_explicit);
-
-  file_mips_isa = mips_opts.isa;
-  file_ase = mips_opts.ase;
-  mips_opts.gp32 = file_mips_gp32;
-  mips_opts.fp32 = file_mips_fp32;
-  mips_opts.soft_float = file_mips_soft_float;
-  mips_opts.single_float = file_mips_single_float;
-
-  mips_check_isa_supports_ases ();
-
   if (mips_flag_mdebug < 0)
     mips_flag_mdebug = 0;
 }
@@ -14119,6 +14578,8 @@ md_pcrel_from (fixS *fixP)
     case BFD_RELOC_MICROMIPS_16_PCREL_S1:
     case BFD_RELOC_MICROMIPS_JMP:
     case BFD_RELOC_16_PCREL_S2:
+    case BFD_RELOC_MIPS_21_PCREL_S2:
+    case BFD_RELOC_MIPS_26_PCREL_S2:
     case BFD_RELOC_MIPS_JMP:
       /* Return the address of the delay slot.  */
       return addr + 4;
@@ -14284,6 +14745,17 @@ mips_force_relocation (fixS *fixp)
       || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
     return 1;
 
+  /* We want all PC-relative relocations to be kept for R6 relaxation.  */
+  if (ISA_IS_R6 (mips_opts.isa)
+      && (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
+         || fixp->fx_r_type == BFD_RELOC_MIPS_21_PCREL_S2
+         || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
+         || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
+         || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+         || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+         || fixp->fx_r_type == BFD_RELOC_LO16_PCREL))
+    return 1;
+
   return 0;
 }
 
@@ -14328,6 +14800,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       case BFD_RELOC_MICROMIPS_10_PCREL_S1:
       case BFD_RELOC_MICROMIPS_16_PCREL_S1:
       case BFD_RELOC_32_PCREL:
+      case BFD_RELOC_MIPS_21_PCREL_S2:
+      case BFD_RELOC_MIPS_26_PCREL_S2:
+      case BFD_RELOC_MIPS_18_PCREL_S3:
+      case BFD_RELOC_MIPS_19_PCREL_S2:
+      case BFD_RELOC_HI16_S_PCREL:
+      case BFD_RELOC_LO16_PCREL:
        break;
 
       case BFD_RELOC_32:
@@ -14520,6 +14998,38 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        md_number_to_chars (buf, *valP, fixP->fx_size);
       break;
 
+    case BFD_RELOC_MIPS_21_PCREL_S2:
+    case BFD_RELOC_MIPS_26_PCREL_S2:
+      if ((*valP & 0x3) != 0)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("branch to misaligned address (%lx)"), (long) *valP);
+
+      gas_assert (!fixP->fx_done);
+      break;
+
+    case BFD_RELOC_MIPS_18_PCREL_S3:
+      if ((*valP & 0x7) != 0)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("PC-relative access to misaligned address (%lx)"),
+                     (long) *valP);
+
+      gas_assert (!fixP->fx_done);
+      break;
+
+    case BFD_RELOC_MIPS_19_PCREL_S2:
+      if ((*valP & 0x3) != 0)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("PC-relative access to misaligned address (%lx)"),
+                     (long) *valP);
+
+      gas_assert (!fixP->fx_done);
+      break;
+
+    case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_LO16_PCREL:
+      gas_assert (!fixP->fx_done);
+      break;
+
     case BFD_RELOC_16_PCREL_S2:
       if ((*valP & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -14980,30 +15490,11 @@ struct mips_option_stack
 
 static struct mips_option_stack *mips_opts_stack;
 
-/* Handle the .set pseudo-op.  */
-
-static void
-s_mipsset (int x ATTRIBUTE_UNUSED)
+static bfd_boolean
+parse_code_option (char * name)
 {
-  char *name = input_line_pointer, ch;
   const struct mips_ase *ase;
-
-  while (!is_end_of_line[(unsigned char) *input_line_pointer])
-    ++input_line_pointer;
-  ch = *input_line_pointer;
-  *input_line_pointer = '\0';
-
-  if (strcmp (name, "reorder") == 0)
-    {
-      if (mips_opts.noreorder)
-       end_noreorder ();
-    }
-  else if (strcmp (name, "noreorder") == 0)
-    {
-      if (!mips_opts.noreorder)
-       start_noreorder ();
-    }
-  else if (strncmp (name, "at=", 3) == 0)
+  if (strncmp (name, "at=", 3) == 0)
     {
       char *s = name + 3;
 
@@ -15011,61 +15502,27 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        as_bad (_("unrecognized register name `%s'"), s);
     }
   else if (strcmp (name, "at") == 0)
-    {
-      mips_opts.at = ATREG;
-    }
+    mips_opts.at = ATREG;
   else if (strcmp (name, "noat") == 0)
-    {
-      mips_opts.at = ZERO;
-    }
-  else if (strcmp (name, "macro") == 0)
-    {
-      mips_opts.warn_about_macros = 0;
-    }
-  else if (strcmp (name, "nomacro") == 0)
-    {
-      if (mips_opts.noreorder == 0)
-       as_bad (_("`noreorder' must be set before `nomacro'"));
-      mips_opts.warn_about_macros = 1;
-    }
+    mips_opts.at = ZERO;
   else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
-    {
-      mips_opts.nomove = 0;
-    }
+    mips_opts.nomove = 0;
   else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
-    {
-      mips_opts.nomove = 1;
-    }
+    mips_opts.nomove = 1;
   else if (strcmp (name, "bopt") == 0)
-    {
-      mips_opts.nobopt = 0;
-    }
+    mips_opts.nobopt = 0;
   else if (strcmp (name, "nobopt") == 0)
-    {
-      mips_opts.nobopt = 1;
-    }
-  else if (strcmp (name, "gp=default") == 0)
-    mips_opts.gp32 = file_mips_gp32;
+    mips_opts.nobopt = 1;
   else if (strcmp (name, "gp=32") == 0)
-    mips_opts.gp32 = 1;
+    mips_opts.gp = 32;
   else if (strcmp (name, "gp=64") == 0)
-    {
-      if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_warn (_("%s isa does not support 64-bit registers"),
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.gp32 = 0;
-    }
-  else if (strcmp (name, "fp=default") == 0)
-    mips_opts.fp32 = file_mips_fp32;
+    mips_opts.gp = 64;
   else if (strcmp (name, "fp=32") == 0)
-    mips_opts.fp32 = 1;
+    mips_opts.fp = 32;
+  else if (strcmp (name, "fp=xx") == 0)
+    mips_opts.fp = 0;
   else if (strcmp (name, "fp=64") == 0)
-    {
-      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_warn (_("%s isa does not support 64-bit floating point registers"),
-                mips_cpu_info_from_isa (mips_opts.isa)->name);
-      mips_opts.fp32 = 0;
-    }
+    mips_opts.fp = 64;
   else if (strcmp (name, "softfloat") == 0)
     mips_opts.soft_float = 1;
   else if (strcmp (name, "hardfloat") == 0)
@@ -15074,47 +15531,35 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.single_float = 1;
   else if (strcmp (name, "doublefloat") == 0)
     mips_opts.single_float = 0;
+  else if (strcmp (name, "nooddspreg") == 0)
+    mips_opts.oddspreg = 0;
+  else if (strcmp (name, "oddspreg") == 0)
+    mips_opts.oddspreg = 1;
   else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
-    {
-      if (mips_opts.micromips == 1)
-       as_fatal (_("`mips16' cannot be used with `micromips'"));
-      mips_opts.mips16 = 1;
-    }
+    mips_opts.mips16 = 1;
   else if (strcmp (name, "nomips16") == 0
           || strcmp (name, "noMIPS-16") == 0)
     mips_opts.mips16 = 0;
   else if (strcmp (name, "micromips") == 0)
-    {
-      if (mips_opts.mips16 == 1)
-       as_fatal (_("`micromips' cannot be used with `mips16'"));
-      mips_opts.micromips = 1;
-    }
+    mips_opts.micromips = 1;
   else if (strcmp (name, "nomicromips") == 0)
     mips_opts.micromips = 0;
   else if (name[0] == 'n'
           && name[1] == 'o'
           && (ase = mips_lookup_ase (name + 2)))
-    mips_set_ase (ase, FALSE);
+    mips_set_ase (ase, &mips_opts, FALSE);
   else if ((ase = mips_lookup_ase (name)))
-    mips_set_ase (ase, TRUE);
+    mips_set_ase (ase, &mips_opts, TRUE);
   else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
     {
-      int reset = 0;
-
       /* Permit the user to change the ISA and architecture on the fly.
         Needless to say, misuse can cause serious problems.  */
-      if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
-       {
-         reset = 1;
-         mips_opts.isa = file_mips_isa;
-         mips_opts.arch = file_mips_arch;
-       }
-      else if (strncmp (name, "arch=", 5) == 0)
+      if (strncmp (name, "arch=", 5) == 0)
        {
          const struct mips_cpu_info *p;
 
-         p = mips_parse_cpu("internal use", name + 5);
+         p = mips_parse_cpu ("internal use", name + 5);
          if (!p)
            as_bad (_("unknown architecture %s"), name + 5);
          else
@@ -15127,7 +15572,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        {
          const struct mips_cpu_info *p;
 
-         p = mips_parse_cpu("internal use", name);
+         p = mips_parse_cpu ("internal use", name);
          if (!p)
            as_bad (_("unknown ISA level %s"), name + 4);
          else
@@ -15138,46 +15583,6 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        }
       else
        as_bad (_("unknown ISA or architecture %s"), name);
-
-      switch (mips_opts.isa)
-       {
-       case  0:
-         break;
-       case ISA_MIPS1:
-       case ISA_MIPS2:
-       case ISA_MIPS32:
-       case ISA_MIPS32R2:
-       case ISA_MIPS32R3:
-       case ISA_MIPS32R5:
-         mips_opts.gp32 = 1;
-         mips_opts.fp32 = 1;
-         break;
-       case ISA_MIPS3:
-       case ISA_MIPS4:
-       case ISA_MIPS5:
-       case ISA_MIPS64:
-       case ISA_MIPS64R2:
-       case ISA_MIPS64R3:
-       case ISA_MIPS64R5:
-         mips_opts.gp32 = 0;
-         if (mips_opts.arch == CPU_R5900)
-           {
-               mips_opts.fp32 = 1;
-           }
-         else
-           {
-         mips_opts.fp32 = 0;
-           }
-         break;
-       default:
-         as_bad (_("unknown ISA level %s"), name + 4);
-         break;
-       }
-      if (reset)
-       {
-         mips_opts.gp32 = file_mips_gp32;
-         mips_opts.fp32 = file_mips_fp32;
-       }
     }
   else if (strcmp (name, "autoextend") == 0)
     mips_opts.noautoextend = 0;
@@ -15187,6 +15592,68 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.insn32 = TRUE;
   else if (strcmp (name, "noinsn32") == 0)
     mips_opts.insn32 = FALSE;
+  else if (strcmp (name, "sym32") == 0)
+    mips_opts.sym32 = TRUE;
+  else if (strcmp (name, "nosym32") == 0)
+    mips_opts.sym32 = FALSE;
+  else
+    return FALSE;
+  return TRUE;
+}
+
+/* Handle the .set pseudo-op.  */
+
+static void
+s_mipsset (int x ATTRIBUTE_UNUSED)
+{
+  char *name = input_line_pointer, ch;
+  int prev_isa = mips_opts.isa;
+
+  file_mips_check_options ();
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+  ch = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (strchr (name, ','))
+    {
+      /* Generic ".set" directive; use the generic handler.  */
+      *input_line_pointer = ch;
+      input_line_pointer = name;
+      s_set (0);
+      return;
+    }
+
+  if (strcmp (name, "reorder") == 0)
+    {
+      if (mips_opts.noreorder)
+       end_noreorder ();
+    }
+  else if (strcmp (name, "noreorder") == 0)
+    {
+      if (!mips_opts.noreorder)
+       start_noreorder ();
+    }
+  else if (strcmp (name, "macro") == 0)
+    mips_opts.warn_about_macros = 0;
+  else if (strcmp (name, "nomacro") == 0)
+    {
+      if (mips_opts.noreorder == 0)
+       as_bad (_("`noreorder' must be set before `nomacro'"));
+      mips_opts.warn_about_macros = 1;
+    }
+  else if (strcmp (name, "gp=default") == 0)
+    mips_opts.gp = file_mips_opts.gp;
+  else if (strcmp (name, "fp=default") == 0)
+    mips_opts.fp = file_mips_opts.fp;
+  else if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
+    {
+      mips_opts.isa = file_mips_opts.isa;
+      mips_opts.arch = file_mips_opts.arch;
+      mips_opts.gp = file_mips_opts.gp;
+      mips_opts.fp = file_mips_opts.fp;
+    }
   else if (strcmp (name, "push") == 0)
     {
       struct mips_option_stack *s;
@@ -15217,23 +15684,87 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
          free (s);
        }
     }
-  else if (strcmp (name, "sym32") == 0)
-    mips_opts.sym32 = TRUE;
-  else if (strcmp (name, "nosym32") == 0)
-    mips_opts.sym32 = FALSE;
-  else if (strchr (name, ','))
+  else if (!parse_code_option (name))
+    as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+
+  /* The use of .set [arch|cpu]= historically 'fixes' the width of gp and fp
+     registers based on what is supported by the arch/cpu.  */
+  if (mips_opts.isa != prev_isa)
     {
-      /* Generic ".set" directive; use the generic handler.  */
-      *input_line_pointer = ch;
-      input_line_pointer = name;
-      s_set (0);
-      return;
+      switch (mips_opts.isa)
+       {
+       case 0:
+         break;
+       case ISA_MIPS1:
+         /* MIPS I cannot support FPXX.  */
+         mips_opts.fp = 32;
+         /* fall-through.  */
+       case ISA_MIPS2:
+       case ISA_MIPS32:
+       case ISA_MIPS32R2:
+       case ISA_MIPS32R3:
+       case ISA_MIPS32R5:
+         mips_opts.gp = 32;
+         if (mips_opts.fp != 0)
+           mips_opts.fp = 32;
+         break;
+       case ISA_MIPS32R6:
+         mips_opts.gp = 32;
+         mips_opts.fp = 64;
+         break;
+       case ISA_MIPS3:
+       case ISA_MIPS4:
+       case ISA_MIPS5:
+       case ISA_MIPS64:
+       case ISA_MIPS64R2:
+       case ISA_MIPS64R3:
+       case ISA_MIPS64R5:
+       case ISA_MIPS64R6:
+         mips_opts.gp = 64;
+         if (mips_opts.fp != 0)
+           {
+             if (mips_opts.arch == CPU_R5900)
+               mips_opts.fp = 32;
+             else
+               mips_opts.fp = 64;
+           }
+         break;
+       default:
+         as_bad (_("unknown ISA level %s"), name + 4);
+         break;
+       }
     }
-  else
+
+  mips_check_options (&mips_opts, FALSE);
+
+  mips_check_isa_supports_ases ();
+  *input_line_pointer = ch;
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the .module pseudo-op.  */
+
+static void
+s_module (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name = input_line_pointer, ch;
+
+  while (!is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+  ch = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (!file_mips_opts_checked)
     {
-      as_warn (_("tried to set unrecognized symbol: %s\n"), name);
+      if (!parse_code_option (name))
+       as_bad (_(".module used with unrecognized symbol: %s\n"), name);
+
+      /* Update module level settings from mips_opts.  */
+      file_mips_opts = mips_opts;
     }
-  mips_check_isa_supports_ases ();
+  else
+    as_bad (_(".module is not permitted after generating code"));
+
   *input_line_pointer = ch;
   demand_empty_rest_of_line ();
 }
@@ -15280,6 +15811,8 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
   int reg;
   int in_shared;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cpload is ignored.  */
   if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15357,6 +15890,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   expressionS ex_sym;
   int reg1;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
      We also need NewABI support.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15460,6 +15995,8 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
 static void
 s_cplocal (int ignore ATTRIBUTE_UNUSED)
 {
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is not NewABI code,
      .cplocal is ignored.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15488,6 +16025,8 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, or if this is NewABI code,
      .cprestore is ignored.  */
   if (mips_pic != SVR4_PIC || HAVE_NEWABI)
@@ -15535,6 +16074,8 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
+  file_mips_check_options ();
+
   /* If we are not generating SVR4 PIC code, .cpreturn is ignored.
      We also need NewABI support.  */
   if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
@@ -15769,6 +16310,8 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
 {
   int reg;
 
+  file_mips_check_options ();
+
   /* This is ignored when not generating SVR4 PIC code.  */
   if (mips_pic != SVR4_PIC)
     {
@@ -15819,10 +16362,16 @@ s_nan (int ignore ATTRIBUTE_UNUSED)
 
   if (i == sizeof (str_2008) - 1
       && memcmp (input_line_pointer, str_2008, i) == 0)
-    mips_flag_nan2008 = TRUE;
+    mips_nan2008 = 1;
   else if (i == sizeof (str_legacy) - 1
           && memcmp (input_line_pointer, str_legacy, i) == 0)
-    mips_flag_nan2008 = FALSE;
+    {
+      if (ISA_HAS_LEGACY_NAN (file_mips_opts.isa))
+       mips_nan2008 = 0;
+      else
+       as_bad (_("`%s' does not support legacy NaN"),
+                 mips_cpu_info_from_isa (file_mips_opts.isa)->name);
+    }
   else
     as_bad (_("bad .nan directive"));
 
@@ -16519,8 +17068,11 @@ mips_fix_adjustable (fixS *fixp)
   /* There is no place to store an in-place offset for JALR relocations.
      Likewise an in-range offset of limited PC-relative relocations may
      overflow the in-place relocatable field if recalculated against the
-     start address of the symbol's containing section.  */
-  if (HAVE_IN_PLACE_ADDENDS
+     start address of the symbol's containing section.
+
+     Also, PC relative relocations for MIPS R6 need to be symbol rather than
+     section relative to allow linker relaxations to be performed later on.  */
+  if ((HAVE_IN_PLACE_ADDENDS || ISA_IS_R6 (mips_opts.isa))
       && (limited_pcrel_reloc_p (fixp->fx_r_type)
          || jalr_reloc_p (fixp->fx_r_type)))
     return 0;
@@ -16600,7 +17152,13 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
-                 || fixp->fx_r_type == BFD_RELOC_32_PCREL);
+                 || fixp->fx_r_type == BFD_RELOC_32_PCREL
+                 || fixp->fx_r_type == BFD_RELOC_MIPS_21_PCREL_S2
+                 || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
+                 || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
+                 || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+                 || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+                 || fixp->fx_r_type == BFD_RELOC_LO16_PCREL);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
@@ -17334,11 +17892,123 @@ mips_add_dot_label (symbolS *sym)
     mips_compressed_mark_label (sym);
 }
 \f
+/* Converting ASE flags from internal to .MIPS.abiflags values.  */
+static unsigned int
+mips_convert_ase_flags (int ase)
+{
+  unsigned int ext_ases = 0;
+
+  if (ase & ASE_DSP)
+    ext_ases |= AFL_ASE_DSP;
+  if (ase & ASE_DSPR2)
+    ext_ases |= AFL_ASE_DSPR2;
+  if (ase & ASE_EVA)
+    ext_ases |= AFL_ASE_EVA;
+  if (ase & ASE_MCU)
+    ext_ases |= AFL_ASE_MCU;
+  if (ase & ASE_MDMX)
+    ext_ases |= AFL_ASE_MDMX;
+  if (ase & ASE_MIPS3D)
+    ext_ases |= AFL_ASE_MIPS3D;
+  if (ase & ASE_MT)
+    ext_ases |= AFL_ASE_MT;
+  if (ase & ASE_SMARTMIPS)
+    ext_ases |= AFL_ASE_SMARTMIPS;
+  if (ase & ASE_VIRT)
+    ext_ases |= AFL_ASE_VIRT;
+  if (ase & ASE_MSA)
+    ext_ases |= AFL_ASE_MSA;
+  if (ase & ASE_XPA)
+    ext_ases |= AFL_ASE_XPA;
+
+  return ext_ases;
+}
 /* Some special processing for a MIPS ELF file.  */
 
 void
 mips_elf_final_processing (void)
 {
+  int fpabi;
+  Elf_Internal_ABIFlags_v0 flags;
+
+  flags.version = 0;
+  flags.isa_rev = 0;
+  switch (file_mips_opts.isa)
+    {
+    case INSN_ISA1:
+      flags.isa_level = 1;
+      break;
+    case INSN_ISA2:
+      flags.isa_level = 2;
+      break;
+    case INSN_ISA3:
+      flags.isa_level = 3;
+      break;
+    case INSN_ISA4:
+      flags.isa_level = 4;
+      break;
+    case INSN_ISA5:
+      flags.isa_level = 5;
+      break;
+    case INSN_ISA32:
+      flags.isa_level = 32;
+      flags.isa_rev = 1;
+      break;
+    case INSN_ISA32R2:
+      flags.isa_level = 32;
+      flags.isa_rev = 2;
+      break;
+    case INSN_ISA32R3:
+      flags.isa_level = 32;
+      flags.isa_rev = 3;
+      break;
+    case INSN_ISA32R5:
+      flags.isa_level = 32;
+      flags.isa_rev = 5;
+      break;
+    case INSN_ISA64:
+      flags.isa_level = 64;
+      flags.isa_rev = 1;
+      break;
+    case INSN_ISA64R2:
+      flags.isa_level = 64;
+      flags.isa_rev = 2;
+      break;
+    case INSN_ISA64R3:
+      flags.isa_level = 64;
+      flags.isa_rev = 3;
+      break;
+    case INSN_ISA64R5:
+      flags.isa_level = 64;
+      flags.isa_rev = 5;
+      break;
+    }
+
+  flags.gpr_size = file_mips_opts.gp == 32 ? AFL_REG_32 : AFL_REG_64;
+  flags.cpr1_size = file_mips_opts.soft_float ? AFL_REG_NONE
+                   : (file_mips_opts.ase & ASE_MSA) ? AFL_REG_128
+                   : (file_mips_opts.fp == 64) ? AFL_REG_64
+                   : AFL_REG_32;
+  flags.cpr2_size = AFL_REG_NONE;
+  flags.fp_abi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+                                           Tag_GNU_MIPS_ABI_FP);
+  flags.isa_ext = bfd_mips_isa_ext (stdoutput);
+  flags.ases = mips_convert_ase_flags (file_mips_opts.ase);
+  if (file_ase_mips16)
+    flags.ases |= AFL_ASE_MIPS16;
+  if (file_ase_micromips)
+    flags.ases |= AFL_ASE_MICROMIPS;
+  flags.flags1 = 0;
+  if ((ISA_HAS_ODD_SINGLE_FPR (file_mips_opts.isa, file_mips_opts.arch)
+       || file_mips_opts.fp == 64)
+      && file_mips_opts.oddspreg)
+    flags.flags1 |= AFL_FLAGS1_ODDSPREG;
+  flags.flags2 = 0;
+
+  bfd_mips_elf_swap_abiflags_v0_out (stdoutput, &flags,
+                                    ((Elf_External_ABIFlags_v0 *)
+                                    mips_flags_frag));
+
   /* Write out the register information.  */
   if (mips_abi != N64_ABI)
     {
@@ -17390,7 +18060,7 @@ mips_elf_final_processing (void)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
   if (file_ase_micromips)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
-  if (file_ase & ASE_MDMX)
+  if (file_mips_opts.ase & ASE_MDMX)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
 
   /* Set the MIPS ELF ABI flags.  */
@@ -17400,7 +18070,7 @@ mips_elf_final_processing (void)
     elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
   else if (mips_abi == EABI_ABI)
     {
-      if (!file_mips_gp32)
+      if (file_mips_opts.gp == 64)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
@@ -17413,11 +18083,13 @@ mips_elf_final_processing (void)
   if (mips_32bitmode)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
 
-  if (mips_flag_nan2008)
+  if (mips_nan2008 == 1)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
 
   /* 32 bit code with 64 bit FP registers.  */
-  if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
+  fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+                                   Tag_GNU_MIPS_ABI_FP);
+  if (fpabi == Val_GNU_MIPS_ABI_FP_OLD_64)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_FP64;
 }
 \f
@@ -17521,19 +18193,6 @@ mips_handle_align (fragS *fragp)
   fragp->fr_var = size;
 }
 
-static void
-md_obj_begin (void)
-{
-}
-
-static void
-md_obj_end (void)
-{
-  /* Check for premature end, nesting errors, etc.  */
-  if (cur_proc_ptr)
-    as_warn (_("missing .end at end of assembly"));
-}
-
 static long
 get_number (void)
 {
@@ -17870,10 +18529,12 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "mips32r2",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R2, CPU_MIPS32R2 },
   { "mips32r3",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R3, CPU_MIPS32R3 },
   { "mips32r5",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R5, CPU_MIPS32R5 },
+  { "mips32r6",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R6, CPU_MIPS32R6 },
   { "mips64",         MIPS_CPU_IS_ISA, 0,      ISA_MIPS64,   CPU_MIPS64 },
   { "mips64r2",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS64R2, CPU_MIPS64R2 },
   { "mips64r3",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS64R3, CPU_MIPS64R3 },
   { "mips64r5",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS64R5, CPU_MIPS64R5 },
+  { "mips64r6",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS64R6, CPU_MIPS64R6 },
 
   /* MIPS I */
   { "r3000",          0, 0,                    ISA_MIPS1,    CPU_R3000 },
@@ -18091,8 +18752,9 @@ mips_parse_cpu (const char *option, const char *cpu_string)
       if (ABI_NEEDS_64BIT_REGS (mips_abi))
        return mips_cpu_info_from_isa (ISA_MIPS3);
 
-      if (file_mips_gp32 >= 0)
-       return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
+      if (file_mips_opts.gp >= 0)
+       return mips_cpu_info_from_isa (file_mips_opts.gp == 32
+                                      ? ISA_MIPS1 : ISA_MIPS3);
 
       return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
                                     ? ISA_MIPS3
@@ -18188,10 +18850,12 @@ MIPS options:\n\
 -mips32r2               generate MIPS32 release 2 ISA instructions\n\
 -mips32r3               generate MIPS32 release 3 ISA instructions\n\
 -mips32r5               generate MIPS32 release 5 ISA instructions\n\
+-mips32r6               generate MIPS32 release 6 ISA instructions\n\
 -mips64                 generate MIPS64 ISA instructions\n\
 -mips64r2               generate MIPS64 release 2 ISA instructions\n\
 -mips64r3               generate MIPS64 release 3 ISA instructions\n\
 -mips64r5               generate MIPS64 release 5 ISA instructions\n\
+-mips64r6               generate MIPS64 release 6 ISA instructions\n\
 -march=CPU/-mtune=CPU  generate code/schedule for CPU, where CPU is one of:\n"));
 
   first = 1;
@@ -18342,3 +19006,91 @@ tc_mips_regname_to_dw2regnum (char *regname)
 
   return regnum;
 }
+
+/* Implement CONVERT_SYMBOLIC_ATTRIBUTE.
+   Given a symbolic attribute NAME, return the proper integer value.
+   Returns -1 if the attribute is not known.  */
+
+int
+mips_convert_symbolic_attribute (const char *name)
+{
+  static const struct
+  {
+    const char * name;
+    const int    tag;
+  }
+  attribute_table[] =
+    {
+#define T(tag) {#tag, tag}
+      T (Tag_GNU_MIPS_ABI_FP),
+      T (Tag_GNU_MIPS_ABI_MSA),
+#undef T
+    };
+  unsigned int i;
+
+  if (name == NULL)
+    return -1;
+
+  for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
+    if (streq (name, attribute_table[i].name))
+      return attribute_table[i].tag;
+
+  return -1;
+}
+
+void
+md_mips_end (void)
+{
+  int fpabi = Val_GNU_MIPS_ABI_FP_ANY;
+
+  mips_emit_delays ();
+  if (cur_proc_ptr)
+    as_warn (_("missing .end at end of assembly"));
+
+  /* Just in case no code was emitted, do the consistency check.  */
+  file_mips_check_options ();
+
+  /* Set a floating-point ABI if the user did not.  */
+  if (obj_elf_seen_attribute (OBJ_ATTR_GNU, Tag_GNU_MIPS_ABI_FP))
+    {
+      /* Perform consistency checks on the floating-point ABI.  */
+      fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+                                       Tag_GNU_MIPS_ABI_FP);
+      if (fpabi != Val_GNU_MIPS_ABI_FP_ANY)
+       check_fpabi (fpabi);
+    }
+  else
+    {
+      /* Soft-float gets precedence over single-float, the two options should
+         not be used together so this should not matter.  */
+      if (file_mips_opts.soft_float == 1)
+       fpabi = Val_GNU_MIPS_ABI_FP_SOFT;
+      /* Single-float gets precedence over all double_float cases.  */
+      else if (file_mips_opts.single_float == 1)
+       fpabi = Val_GNU_MIPS_ABI_FP_SINGLE;
+      else
+       {
+         switch (file_mips_opts.fp)
+           {
+           case 32:
+             if (file_mips_opts.gp == 32)
+               fpabi = Val_GNU_MIPS_ABI_FP_DOUBLE;
+             break;
+           case 0:
+             fpabi = Val_GNU_MIPS_ABI_FP_XX;
+             break;
+           case 64:
+             if (file_mips_opts.gp == 32 && !file_mips_opts.oddspreg)
+               fpabi = Val_GNU_MIPS_ABI_FP_64A;
+             else if (file_mips_opts.gp == 32)
+               fpabi = Val_GNU_MIPS_ABI_FP_64;
+             else
+               fpabi = Val_GNU_MIPS_ABI_FP_DOUBLE;
+             break;
+           }
+       }
+
+      bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU,
+                               Tag_GNU_MIPS_ABI_FP, fpabi);
+    }
+}
This page took 0.069742 seconds and 4 git commands to generate.