2014-11-05 Jan-Benedict Glaw <jbglaw@lug-owl.de>
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 4814a699fe6e92ee807df4fa1f55219957f1b1ef..607689b5670ceb75d9fb2ecc74cbc2db02162b9c 100644 (file)
@@ -89,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
@@ -257,13 +258,20 @@ 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;
+
+  /* 1 if single-precision operations on odd-numbered registers are
+     allowed.  */
+  int oddspreg;
 };
 
 /* Specifies whether module level options have been checked yet.  */
 static bfd_boolean file_mips_opts_checked = FALSE;
 
-/* True if -mnan=2008, false if -mnan=legacy.  */
-static bfd_boolean mips_flag_nan2008 = FALSE;
+/* 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;
 
 /* 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
@@ -275,7 +283,7 @@ static struct mips_set_options file_mips_opts =
   /* 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
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1
 };
 
 /* This is similar to file_mips_opts, but for the current set of options.  */
@@ -286,7 +294,7 @@ static struct mips_set_options mips_opts =
   /* 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
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1
 };
 
 /* Which bits of file_ase were explicitly set or cleared by ASE options.  */
@@ -345,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                  \
@@ -353,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)                \
@@ -363,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.  */
@@ -374,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))    \
    )
@@ -384,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. */
@@ -408,6 +430,24 @@ 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)
+
+/*  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)
@@ -470,7 +510,8 @@ static int mips_32bitmode = 0;
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
 /* True if CPU is in the Octeon family */
-#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP || (CPU) == CPU_OCTEON2)
+#define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
+                           || (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
 
 /* True if CPU has seq/sne and seqi/snei instructions.  */
 #define CPU_HAS_SEQ(CPU)       (CPU_IS_OCTEON (CPU))
@@ -496,10 +537,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                    \
@@ -526,8 +569,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.  */
@@ -1344,9 +1387,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,
@@ -1407,6 +1452,7 @@ enum options
     OPTION_CONSTRUCT_FLOATS,
     OPTION_NO_CONSTRUCT_FLOATS,
     OPTION_FP64,
+    OPTION_FPXX,
     OPTION_GP64,
     OPTION_RELAX_BRANCH,
     OPTION_NO_RELAX_BRANCH,
@@ -1434,6 +1480,8 @@ enum options
     OPTION_NO_PDR,
     OPTION_MVXWORKS_PIC,
     OPTION_NAN,
+    OPTION_ODD_SPREG,
+    OPTION_NO_ODD_SPREG,
     OPTION_END_OF_ENUM
   };
 
@@ -1453,9 +1501,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},
@@ -1526,6 +1576,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},
@@ -1539,6 +1590,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
@@ -1592,55 +1645,70 @@ 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.  */
@@ -1793,7 +1861,7 @@ static void mips_compressed_mark_labels (void);
 static inline void
 mips_clear_insn_labels (void)
 {
-  register struct insn_label_list **pl;
+  struct insn_label_list **pl;
   segment_info_type *si;
 
   if (now_seg)
@@ -1902,6 +1970,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;
@@ -1953,6 +2024,16 @@ 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.fp != 64
       && (warned_fp32 & ase->flags) != ase->flags)
@@ -3281,7 +3362,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;
@@ -3612,6 +3693,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);
@@ -3635,6 +3722,88 @@ md_begin (void)
     init_vr4120_conflicts ();
 }
 
+static inline void
+fpabi_incompatible_with (int fpabi, const char *what)
+{
+  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
@@ -3653,6 +3822,12 @@ mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
   /* 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"));
@@ -3665,14 +3840,29 @@ mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
       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.
@@ -3721,6 +3911,9 @@ file_mips_check_options (void)
               && 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;
@@ -3728,6 +3921,16 @@ file_mips_check_options (void)
 
   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
@@ -3748,6 +3951,12 @@ file_mips_check_options (void)
     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)
@@ -3927,9 +4136,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:
@@ -4232,6 +4447,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 ();
 
@@ -4377,39 +4606,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.  */
@@ -4565,9 +4797,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;
@@ -4632,9 +4864,16 @@ check_regno (struct mips_arg_info *arg,
 
   if (type == OP_REG_FP
       && (regno & 1) != 0
-      && FPR_SIZE != 64
       && !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)
     {
@@ -5014,6 +5253,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
@@ -5407,6 +5698,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.  */
 
@@ -5488,13 +5798,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 || !(FPR_SIZE == 64 && GPR_SIZE == 32))
+      /* 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)
@@ -5504,7 +5817,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 ? GPR_SIZE == 32 : FPR_SIZE != 64)
+      if (GPR_SIZE == 32 || (!using_gprs && FPR_SIZE != 64))
        {
          imm->X_op = O_constant;
          offset->X_op = O_constant;
@@ -5680,6 +5993,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 ();
 }
@@ -5709,7 +6031,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;
 
@@ -5827,7 +6149,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;
@@ -5841,7 +6163,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
@@ -5880,6 +6202,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;
 }
 
@@ -6737,6 +7067,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;
@@ -7401,12 +7765,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;
 
@@ -7492,7 +7877,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)
@@ -7962,10 +8347,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])
@@ -8143,7 +8531,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;
        }
@@ -10912,7 +11300,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;
@@ -10942,7 +11332,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;
@@ -10970,13 +11362,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";
@@ -11046,7 +11442,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;
@@ -11069,18 +11467,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";
@@ -11089,8 +11495,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";
@@ -11106,7 +11516,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;
@@ -11686,14 +12098,18 @@ macro (struct mips_cl_insn *ip, char *str)
        {
          used_at = 1;
          load_register (AT, &imm_expr, FPR_SIZE == 64);
-         if (FPR_SIZE == 64)
-           {
-             gas_assert (GPR_SIZE == 64);
-             macro_build (NULL, "dmtc1", "t,S", AT, op[0]);
-           }
+         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
@@ -12069,11 +12485,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;
@@ -13429,7 +13845,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[] =
@@ -13707,6 +14125,10 @@ md_parse_option (int c, char *arg)
       file_mips_opts.isa = ISA_MIPS32R5;
       break;
 
+    case OPTION_MIPS32R6:
+      file_mips_opts.isa = ISA_MIPS32R6;
+      break;
+
     case OPTION_MIPS64R2:
       file_mips_opts.isa = ISA_MIPS64R2;
       break;
@@ -13719,6 +14141,10 @@ md_parse_option (int c, char *arg)
       file_mips_opts.isa = ISA_MIPS64R5;
       break;
 
+    case OPTION_MIPS64R6:
+      file_mips_opts.isa = ISA_MIPS64R6;
+      break;
+
     case OPTION_MIPS64:
       file_mips_opts.isa = ISA_MIPS64;
       break;
@@ -13939,10 +14365,22 @@ md_parse_option (int c, char *arg)
       file_mips_opts.fp = 32;
       break;
 
+    case OPTION_FPXX:
+      file_mips_opts.fp = 0;
+      break;
+
     case OPTION_FP64:
       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_opts.single_float = 1;
       break;
@@ -14012,9 +14450,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);
@@ -14141,6 +14579,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;
@@ -14306,6 +14746,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;
 }
 
@@ -14350,6 +14801,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:
@@ -14542,6 +14999,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,
@@ -15031,6 +15520,8 @@ parse_code_option (char * name)
     mips_opts.gp = 64;
   else if (strcmp (name, "fp=32") == 0)
     mips_opts.fp = 32;
+  else if (strcmp (name, "fp=xx") == 0)
+    mips_opts.fp = 0;
   else if (strcmp (name, "fp=64") == 0)
     mips_opts.fp = 64;
   else if (strcmp (name, "softfloat") == 0)
@@ -15041,6 +15532,10 @@ parse_code_option (char * name)
     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)
     mips_opts.mips16 = 1;
@@ -15202,13 +15697,21 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        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;
-         mips_opts.fp = 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:
@@ -15217,11 +15720,15 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        case ISA_MIPS64R2:
        case ISA_MIPS64R3:
        case ISA_MIPS64R5:
+       case ISA_MIPS64R6:
          mips_opts.gp = 64;
-         if (mips_opts.arch == CPU_R5900)
-           mips_opts.fp = 32;
-         else
-           mips_opts.fp = 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);
@@ -15838,6 +16345,10 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
 static void
 s_insn (int ignore ATTRIBUTE_UNUSED)
 {
+  file_mips_check_options ();
+  file_ase_mips16 |= mips_opts.mips16;
+  file_ase_micromips |= mips_opts.micromips;
+
   mips_mark_labels ();
 
   demand_empty_rest_of_line ();
@@ -15856,10 +16367,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"));
 
@@ -16556,8 +17073,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;
@@ -16637,7 +17157,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.  */
@@ -17371,11 +17897,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)
     {
@@ -17450,11 +18088,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_opts.fp == 64 && 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
@@ -17894,10 +18534,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 },
@@ -18022,6 +18664,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "octeon",        0, 0,                     ISA_MIPS64R2, CPU_OCTEON },
   { "octeon+",       0, 0,                     ISA_MIPS64R2, CPU_OCTEONP },
   { "octeon2",       0, 0,                     ISA_MIPS64R2, CPU_OCTEON2 },
+  { "octeon3",       0, ASE_VIRT | ASE_VIRT64, ISA_MIPS64R5, CPU_OCTEON3 },
 
   /* RMI Xlr */
   { "xlr",           0, 0,                     ISA_MIPS64,   CPU_XLR },
@@ -18213,10 +18856,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;
@@ -18402,10 +19047,56 @@ mips_convert_symbolic_attribute (const char *name)
 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.047274 seconds and 4 git commands to generate.