Implement CONVERT_SYMBOLIC_ATTRIBUTE for MIPS.
[external/binutils.git] / gas / config / tc-mips.c
index ff1c610..edbab71 100644 (file)
@@ -1,7 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
-   Free Software Foundation, Inc.
+   Copyright (C) 1993-2014 Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
    Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -44,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)
 
@@ -308,8 +308,12 @@ static int file_ase_mips16;
 
 #define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32              \
                              || mips_opts.isa == ISA_MIPS32R2          \
+                             || mips_opts.isa == ISA_MIPS32R3          \
+                             || mips_opts.isa == ISA_MIPS32R5          \
                              || mips_opts.isa == ISA_MIPS64            \
-                             || mips_opts.isa == ISA_MIPS64R2)
+                             || mips_opts.isa == ISA_MIPS64R2          \
+                             || mips_opts.isa == ISA_MIPS64R3          \
+                             || mips_opts.isa == ISA_MIPS64R5)
 
 /* True if any microMIPS code was produced.  */
 static int file_ase_micromips;
@@ -353,7 +357,9 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS4               \
    || (ISA) == ISA_MIPS5               \
    || (ISA) == ISA_MIPS64              \
-   || (ISA) == ISA_MIPS64R2)
+   || (ISA) == ISA_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5)
 
 /*  Return true if ISA supports 64 bit wide float registers.  */
 #define ISA_HAS_64BIT_FPRS(ISA)                \
@@ -361,13 +367,19 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS4               \
    || (ISA) == ISA_MIPS5               \
    || (ISA) == ISA_MIPS32R2            \
+   || (ISA) == ISA_MIPS32R3            \
+   || (ISA) == ISA_MIPS32R5            \
    || (ISA) == ISA_MIPS64              \
-   || (ISA) == ISA_MIPS64R2)
+   || (ISA) == ISA_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5            )
 
 /* Return true if ISA supports 64-bit right rotate (dror et al.)
    instructions.  */
 #define ISA_HAS_DROR(ISA)              \
   ((ISA) == ISA_MIPS64R2               \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5            \
    || (mips_opts.micromips             \
        && ISA_HAS_64BIT_REGS (ISA))    \
    )
@@ -376,7 +388,11 @@ static int mips_32bitmode = 0;
    instructions.  */
 #define ISA_HAS_ROR(ISA)               \
   ((ISA) == ISA_MIPS32R2               \
+   || (ISA) == ISA_MIPS32R3            \
+   || (ISA) == ISA_MIPS32R5            \
    || (ISA) == ISA_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5            \
    || (mips_opts.ase & ASE_SMARTMIPS)  \
    || mips_opts.micromips              \
    )
@@ -385,14 +401,22 @@ static int mips_32bitmode = 0;
 #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_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5)
 
 /* Return true if ISA supports move to/from high part of a 64-bit
    floating-point register. */
 #define ISA_HAS_MXHC1(ISA)             \
   ((ISA) == ISA_MIPS32R2               \
-   || (ISA) == ISA_MIPS64R2)
+   || (ISA) == ISA_MIPS32R3            \
+   || (ISA) == ISA_MIPS32R5            \
+   || (ISA) == ISA_MIPS64R2            \
+   || (ISA) == ISA_MIPS64R3            \
+   || (ISA) == ISA_MIPS64R5)
 
 #define HAVE_32BIT_GPRS                                   \
     (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
@@ -475,8 +499,12 @@ static int mips_32bitmode = 0;
 #define hilo_interlocks \
   (mips_opts.isa == ISA_MIPS32                        \
    || mips_opts.isa == ISA_MIPS32R2                   \
+   || mips_opts.isa == ISA_MIPS32R3                   \
+   || mips_opts.isa == ISA_MIPS32R5                   \
    || mips_opts.isa == ISA_MIPS64                     \
    || mips_opts.isa == ISA_MIPS64R2                   \
+   || mips_opts.isa == ISA_MIPS64R3                   \
+   || mips_opts.isa == ISA_MIPS64R5                   \
    || mips_opts.arch == CPU_R4010                     \
    || mips_opts.arch == CPU_R5900                     \
    || mips_opts.arch == CPU_R10000                    \
@@ -491,7 +519,7 @@ static int mips_32bitmode = 0;
 /* Whether the processor uses hardware interlocks to protect reads
    from the GPRs after they are loaded from memory, and thus does not
    require nops to be inserted.  This applies to instructions marked
-   INSN_LOAD_MEMORY_DELAY.  These nops are only required at MIPS ISA
+   INSN_LOAD_MEMORY.  These nops are only required at MIPS ISA
    level I and microMIPS mode instructions are always interlocked.  */
 #define gpr_interlocks                                \
   (mips_opts.isa != ISA_MIPS1                         \
@@ -865,6 +893,9 @@ static int mips_fix_vr4130;
 /* ...likewise -mfix-24k.  */
 static int mips_fix_24k;
 
+/* ...likewise -mfix-rm7000  */
+static int mips_fix_rm7000;
+
 /* ...likewise -mfix-cn63xxp1 */
 static bfd_boolean mips_fix_cn63xxp1;
 
@@ -1316,7 +1347,11 @@ enum options
     OPTION_MIPS32,
     OPTION_MIPS64,
     OPTION_MIPS32R2,
+    OPTION_MIPS32R3,
+    OPTION_MIPS32R5,
     OPTION_MIPS64R2,
+    OPTION_MIPS64R3,
+    OPTION_MIPS64R5,
     OPTION_MIPS16,
     OPTION_NO_MIPS16,
     OPTION_MIPS3D,
@@ -1329,12 +1364,16 @@ enum options
     OPTION_NO_MT,
     OPTION_VIRT,
     OPTION_NO_VIRT,
+    OPTION_MSA,
+    OPTION_NO_MSA,
     OPTION_SMARTMIPS,
     OPTION_NO_SMARTMIPS,
     OPTION_DSPR2,
     OPTION_NO_DSPR2,
     OPTION_EVA,
     OPTION_NO_EVA,
+    OPTION_XPA,
+    OPTION_NO_XPA,
     OPTION_MICROMIPS,
     OPTION_NO_MICROMIPS,
     OPTION_MCU,
@@ -1352,6 +1391,8 @@ enum options
     OPTION_MNO_7000_HILO_FIX,
     OPTION_FIX_24K,
     OPTION_NO_FIX_24K,
+    OPTION_FIX_RM7000,
+    OPTION_NO_FIX_RM7000,
     OPTION_FIX_LOONGSON2F_JUMP,
     OPTION_NO_FIX_LOONGSON2F_JUMP,
     OPTION_FIX_LOONGSON2F_NOP,
@@ -1415,7 +1456,11 @@ struct option md_longopts[] =
   {"mips32", no_argument, NULL, OPTION_MIPS32},
   {"mips64", no_argument, NULL, OPTION_MIPS64},
   {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
+  {"mips32r3", no_argument, NULL, OPTION_MIPS32R3},
+  {"mips32r5", no_argument, NULL, OPTION_MIPS32R5},
   {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
+  {"mips64r3", no_argument, NULL, OPTION_MIPS64R3},
+  {"mips64r5", no_argument, NULL, OPTION_MIPS64R5},
 
   /* Options which specify Application Specific Extensions (ASEs).  */
   {"mips16", no_argument, NULL, OPTION_MIPS16},
@@ -1440,6 +1485,10 @@ struct option md_longopts[] =
   {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
   {"mvirt", no_argument, NULL, OPTION_VIRT},
   {"mno-virt", no_argument, NULL, OPTION_NO_VIRT},
+  {"mmsa", no_argument, NULL, OPTION_MSA},
+  {"mno-msa", no_argument, NULL, OPTION_NO_MSA},
+  {"mxpa", no_argument, NULL, OPTION_XPA},
+  {"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
 
   /* Old-style architecture options.  Don't add more of these.  */
   {"m4650", no_argument, NULL, OPTION_M4650},
@@ -1465,6 +1514,8 @@ struct option md_longopts[] =
   {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
   {"mfix-24k",    no_argument, NULL, OPTION_FIX_24K},
   {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K},
+  {"mfix-rm7000",    no_argument, NULL, OPTION_FIX_RM7000},
+  {"mno-fix-rm7000", no_argument, NULL, OPTION_NO_FIX_RM7000},
   {"mfix-cn63xxp1", no_argument, NULL, OPTION_FIX_CN63XXP1},
   {"mno-fix-cn63xxp1", no_argument, NULL, OPTION_NO_FIX_CN63XXP1},
 
@@ -1586,7 +1637,15 @@ static const struct mips_ase mips_ases[] = {
 
   { "virt", ASE_VIRT, ASE_VIRT64,
     OPTION_VIRT, OPTION_NO_VIRT,
-    2, 2, 2, 2 }
+    2, 2, 2, 2 },
+
+  { "msa", ASE_MSA, ASE_MSA64,
+    OPTION_MSA, OPTION_NO_MSA,
+    2, 2, 2, 2 },
+
+  { "xpa", ASE_XPA, 0,
+    OPTION_XPA, OPTION_NO_XPA,
+    2, 2, -1, -1 }
 };
 
 /* The set of ASEs that require -mfp64.  */
@@ -1840,6 +1899,12 @@ mips_isa_rev (void)
   if (mips_opts.isa == ISA_MIPS32R2 || mips_opts.isa == ISA_MIPS64R2)
     return 2;
 
+  if (mips_opts.isa == ISA_MIPS32R3 || mips_opts.isa == ISA_MIPS64R3)
+    return 3;
+
+  if (mips_opts.isa == ISA_MIPS32R5 || mips_opts.isa == ISA_MIPS64R5)
+    return 5;
+
   /* microMIPS implies revision 2 or above.  */
   if (mips_opts.micromips)
     return 2;
@@ -2347,7 +2412,7 @@ struct regname {
 };
 
 #define RNUM_MASK      0x00000ff
-#define RTYPE_MASK     0x0efff00
+#define RTYPE_MASK     0x0ffff00
 #define RTYPE_NUM      0x0000100
 #define RTYPE_FPU      0x0000200
 #define RTYPE_FCC      0x0000400
@@ -2363,6 +2428,7 @@ struct regname {
 #define RTYPE_R5900_Q  0x0100000
 #define RTYPE_R5900_R  0x0200000
 #define RTYPE_R5900_ACC        0x0400000
+#define RTYPE_MSA      0x0800000
 #define RWARN          0x8000000
 
 #define GENERIC_REGISTER_NUMBERS \
@@ -2747,8 +2813,11 @@ enum mips_operand_token_type {
   /* A 4-bit XYZW channel mask.  */
   OT_CHANNELS,
 
-  /* An element of a vector, e.g. $v0[1].  */
-  OT_REG_ELEMENT,
+  /* A constant vector index, e.g. [1].  */
+  OT_INTEGER_INDEX,
+
+  /* A register vector index, e.g. [$2].  */
+  OT_REG_INDEX,
 
   /* A continuous range of registers, e.g. $s0-$s4.  */
   OT_REG_RANGE,
@@ -2777,17 +2846,14 @@ struct mips_operand_token
   enum mips_operand_token_type type;
   union
   {
-    /* The register symbol value for an OT_REG.  */
+    /* The register symbol value for an OT_REG or OT_REG_INDEX.  */
     unsigned int regno;
 
     /* The 4-bit channel mask for an OT_CHANNEL_SUFFIX.  */
     unsigned int channels;
 
-    /* The register symbol value and index for an OT_REG_ELEMENT.  */
-    struct {
-      unsigned int regno;
-      addressT index;
-    } reg_element;
+    /* The integer value of an OT_INTEGER_INDEX.  */
+    addressT index;
 
     /* The two register symbol values involved in an OT_REG_RANGE.  */
     struct {
@@ -2948,20 +3014,32 @@ mips_parse_argument_token (char *s, char float_format)
          mips_add_token (&token, OT_REG_RANGE);
          return s;
        }
-      else if (*s == '[')
-       {
-         /* A vector element.  */
-         expressionS element;
 
+      /* Add the register itself.  */
+      token.u.regno = regno1;
+      mips_add_token (&token, OT_REG);
+
+      /* Check for a vector index.  */
+      if (*s == '[')
+       {
          ++s;
          SKIP_SPACE_TABS (s);
-         my_getExpression (&element, s);
-         if (element.X_op != O_constant)
+         if (mips_parse_register (&s, &token.u.regno, NULL))
+           mips_add_token (&token, OT_REG_INDEX);
+         else
            {
-             set_insn_error (0, _("vector element must be constant"));
-             return 0;
+             expressionS element;
+
+             my_getExpression (&element, s);
+             if (element.X_op != O_constant)
+               {
+                 set_insn_error (0, _("vector element must be constant"));
+                 return 0;
+               }
+             s = expr_end;
+             token.u.index = element.X_add_number;
+             mips_add_token (&token, OT_INTEGER_INDEX);
            }
-         s = expr_end;
          SKIP_SPACE_TABS (s);
          if (*s != ']')
            {
@@ -2969,16 +3047,7 @@ mips_parse_argument_token (char *s, char float_format)
              return 0;
            }
          ++s;
-
-         token.u.reg_element.regno = regno1;
-         token.u.reg_element.index = element.X_add_number;
-         mips_add_token (&token, OT_REG_ELEMENT);
-         return s;
        }
-
-      /* Looks like just a plain register.  */
-      token.u.regno = regno1;
-      mips_add_token (&token, OT_REG);
       return s;
     }
 
@@ -3460,6 +3529,10 @@ md_begin (void)
       symbol_table_insert (symbol_new (regname, reg_section,
                                       RTYPE_VI | i, &zero_address_frag));
 
+      /* MSA register.  */
+      snprintf (regname, sizeof (regname) - 1, "$w%d", i);
+      symbol_table_insert (symbol_new (regname, reg_section,
+                                      RTYPE_MSA | i, &zero_address_frag));
     }
 
   obstack_init (&mips_operand_tokens);
@@ -4005,6 +4078,7 @@ operand_reg_mask (const struct mips_cl_insn *insn,
     case OP_PC:
     case OP_VU0_SUFFIX:
     case OP_VU0_MATCH_SUFFIX:
+    case OP_IMM_INDEX:
       abort ();
 
     case OP_REG:
@@ -4050,6 +4124,11 @@ operand_reg_mask (const struct mips_cl_insn *insn,
       if ((vsel & 0x18) == 0x18)
        return 0;
       return 1 << (uval & 31);
+
+    case OP_REG_INDEX:
+      if (!(type_mask & (1 << OP_REG_GP)))
+       return 0;
+      return 1 << insn_extract_operand (insn, operand);
     }
   abort ();
 }
@@ -4139,7 +4218,8 @@ fpr_read_mask (const struct mips_cl_insn *ip)
   unsigned long pinfo;
   unsigned int mask;
 
-  mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+  mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+                            | (1 << OP_REG_MSA)),
                        insn_read_mask (ip->insn_mo));
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
@@ -4157,7 +4237,8 @@ fpr_write_mask (const struct mips_cl_insn *ip)
   unsigned long pinfo;
   unsigned int mask;
 
-  mask = insn_reg_mask (ip, (1 << OP_REG_FP) | (1 << OP_REG_VEC),
+  mask = insn_reg_mask (ip, ((1 << OP_REG_FP) | (1 << OP_REG_VEC)
+                            | (1 << OP_REG_MSA)),
                        insn_write_mask (ip->insn_mo));
   pinfo = ip->insn_mo->pinfo;
   /* Conservatively treat all operands to an FP_D instruction are doubles.
@@ -4365,7 +4446,7 @@ convert_reg_type (const struct mips_opcode *opcode,
          && (opcode->pinfo & (INSN_COPROC_MOVE_DELAY
                               | INSN_COPROC_MEMORY_DELAY
                               | INSN_LOAD_COPROC_DELAY
-                              | INSN_LOAD_MEMORY_DELAY
+                              | INSN_LOAD_MEMORY
                               | INSN_STORE_MEMORY)))
        return RTYPE_FPU | RTYPE_VEC;
       return RTYPE_FPU;
@@ -4408,6 +4489,12 @@ convert_reg_type (const struct mips_opcode *opcode,
 
     case OP_REG_R5900_ACC:
       return RTYPE_R5900_ACC;
+
+    case OP_REG_MSA:
+      return RTYPE_MSA;
+
+    case OP_REG_MSA_CTRL:
+      return RTYPE_NUM;
     }
   abort ();
 }
@@ -5078,7 +5165,7 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
   uval = mips_extract_operand (operand, opcode->match);
   is_qh = (uval != 0);
 
-  if (arg->token->type == OT_REG || arg->token->type == OT_REG_ELEMENT)
+  if (arg->token->type == OT_REG)
     {
       if ((opcode->membership & INSN_5400)
          && strcmp (opcode->name, "rzu.ob") == 0)
@@ -5088,20 +5175,21 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
          return FALSE;
        }
 
+      if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
+       return FALSE;
+      ++arg->token;
+
       /* Check whether this is a vector register or a broadcast of
         a single element.  */
-      if (arg->token->type == OT_REG_ELEMENT)
+      if (arg->token->type == OT_INTEGER_INDEX)
        {
-         if (!match_regno (arg, OP_REG_VEC, arg->token->u.reg_element.regno,
-                           &regno))
-           return FALSE;
-         if (arg->token->u.reg_element.index > (is_qh ? 3 : 7))
+         if (arg->token->u.index > (is_qh ? 3 : 7))
            {
              set_insn_error (arg->argnum, _("invalid element selector"));
              return FALSE;
            }
-         else
-           uval |= arg->token->u.reg_element.index << (is_qh ? 2 : 1) << 5;
+         uval |= arg->token->u.index << (is_qh ? 2 : 1) << 5;
+         ++arg->token;
        }
       else
        {
@@ -5115,15 +5203,12 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
              return FALSE;
            }
 
-         if (!match_regno (arg, OP_REG_VEC, arg->token->u.regno, &regno))
-           return FALSE;
          if (is_qh)
            uval |= MDMX_FMTSEL_VEC_QH << 5;
          else
            uval |= MDMX_FMTSEL_VEC_OB << 5;
        }
       uval |= regno;
-      ++arg->token;
     }
   else
     {
@@ -5146,6 +5231,47 @@ match_mdmx_imm_reg_operand (struct mips_arg_info *arg,
   return TRUE;
 }
 
+/* OP_IMM_INDEX matcher.  */
+
+static bfd_boolean
+match_imm_index_operand (struct mips_arg_info *arg,
+                        const struct mips_operand *operand)
+{
+  unsigned int max_val;
+
+  if (arg->token->type != OT_INTEGER_INDEX)
+    return FALSE;
+
+  max_val = (1 << operand->size) - 1;
+  if (arg->token->u.index > max_val)
+    {
+      match_out_of_range (arg);
+      return FALSE;
+    }
+  insn_insert_operand (arg->insn, operand, arg->token->u.index);
+  ++arg->token;
+  return TRUE;
+}
+
+/* OP_REG_INDEX matcher.  */
+
+static bfd_boolean
+match_reg_index_operand (struct mips_arg_info *arg,
+                        const struct mips_operand *operand)
+{
+  unsigned int regno;
+
+  if (arg->token->type != OT_REG_INDEX)
+    return FALSE;
+
+  if (!match_regno (arg, OP_REG_GP, arg->token->u.regno, &regno))
+    return FALSE;
+
+  insn_insert_operand (arg->insn, operand, regno);
+  ++arg->token;
+  return TRUE;
+}
+
 /* OP_PC matcher.  */
 
 static bfd_boolean
@@ -5426,6 +5552,12 @@ match_operand (struct mips_arg_info *arg,
 
     case OP_VU0_MATCH_SUFFIX:
       return match_vu0_suffix_operand (arg, operand, TRUE);
+
+    case OP_IMM_INDEX:
+      return match_imm_index_operand (arg, operand);
+
+    case OP_REG_INDEX:
+      return match_reg_index_operand (arg, operand);
     }
   abort ();
 }
@@ -5454,7 +5586,7 @@ reg_needs_delay (unsigned int reg)
 
   prev_pinfo = history[0].insn_mo->pinfo;
   if (!mips_opts.noreorder
-      && (((prev_pinfo & INSN_LOAD_MEMORY_DELAY) && !gpr_interlocks)
+      && (((prev_pinfo & INSN_LOAD_MEMORY) && !gpr_interlocks)
          || ((prev_pinfo & INSN_LOAD_COPROC_DELAY) && !cop_interlocks))
       && (gpr_write_mask (&history[0]) & (1 << reg)))
     return TRUE;
@@ -5484,8 +5616,10 @@ classify_vr4120_insn (const char *name)
   return NUM_FIX_VR4120_CLASSES;
 }
 
-#define INSN_ERET  0x42000018
-#define INSN_DERET 0x4200001f
+#define INSN_ERET      0x42000018
+#define INSN_DERET     0x4200001f
+#define INSN_DMULT     0x1c
+#define INSN_DMULTU    0x1d
 
 /* Return the number of instructions that must separate INSN1 and INSN2,
    where INSN1 is the earlier instruction.  Return the worst-case value
@@ -5536,6 +5670,18 @@ insns_between (const struct mips_cl_insn *insn1,
        }
     }
 
+  /* If we're working around PMC RM7000 errata, there must be three
+     nops between a dmult and a load instruction.  */
+  if (mips_fix_rm7000 && !mips_opts.micromips)
+    {
+      if ((insn1->insn_opcode & insn1->insn_mo->mask) == INSN_DMULT
+         || (insn1->insn_opcode & insn1->insn_mo->mask) == INSN_DMULTU)
+       {
+         if (pinfo2 & INSN_LOAD_MEMORY)
+          return 3;
+       }
+    }
+
   /* If working around VR4120 errata, check for combinations that need
      a single intervening instruction.  */
   if (mips_fix_vr4120 && !mips_opts.micromips)
@@ -5558,7 +5704,7 @@ insns_between (const struct mips_cl_insn *insn1,
       /* Check for GPR or coprocessor load delays.  All such delays
         are on the RT register.  */
       /* Itbl support may require additional care here.  */
-      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
+      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY))
          || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
        {
          if (insn2 == NULL || (gpr_read_mask (insn2) & gpr_write_mask (insn1)))
@@ -5997,6 +6143,7 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
 {
   unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
   unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
+  unsigned int fpr_read, prev_fpr_write;
 
   /* -O2 and above is required for this optimization.  */
   if (mips_optimize < 2)
@@ -6071,6 +6218,11 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
   if (gpr_read & prev_gpr_write)
     return FALSE;
 
+  fpr_read = fpr_read_mask (ip);
+  prev_fpr_write = fpr_write_mask (&history[0]);
+  if (fpr_read & prev_fpr_write)
+    return FALSE;
+
   /* If the branch writes a register that the previous
      instruction sets, we can not swap.  */
   gpr_write = gpr_write_mask (ip);
@@ -13425,10 +13577,26 @@ md_parse_option (int c, char *arg)
       file_mips_isa = ISA_MIPS32R2;
       break;
 
+    case OPTION_MIPS32R3:
+      file_mips_isa = ISA_MIPS32R3;
+      break;
+
+    case OPTION_MIPS32R5:
+      file_mips_isa = ISA_MIPS32R5;
+      break;
+
     case OPTION_MIPS64R2:
       file_mips_isa = ISA_MIPS64R2;
       break;
 
+    case OPTION_MIPS64R3:
+      file_mips_isa = ISA_MIPS64R3;
+      break;
+
+    case OPTION_MIPS64R5:
+      file_mips_isa = ISA_MIPS64R5;
+      break;
+
     case OPTION_MIPS64:
       file_mips_isa = ISA_MIPS64;
       break;
@@ -13511,6 +13679,14 @@ md_parse_option (int c, char *arg)
       mips_fix_24k = 0;
       break;
 
+    case OPTION_FIX_RM7000:
+      mips_fix_rm7000 = 1;
+      break;
+
+    case OPTION_NO_FIX_RM7000:
+      mips_fix_rm7000 = 0;
+      break;
+
     case OPTION_FIX_LOONGSON2F_JUMP:
       mips_fix_loongson2f_jump = TRUE;
       break;
@@ -13949,15 +14125,7 @@ md_pcrel_from (fixS *fixP)
       /* Return the address of the delay slot.  */
       return addr + 4;
 
-    case BFD_RELOC_32_PCREL:
-      return addr;
-
     default:
-      /* We have no relocation type for PC relative MIPS16 instructions.  */
-      if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
-       as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("PC relative MIPS16 instruction references"
-                       " a different section"));
       return addr;
     }
 }
@@ -14154,13 +14322,38 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   unsigned long insn;
   reloc_howto_type *howto;
 
-  /* We ignore generic BFD relocations we don't know about.  */
-  howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
-  if (! howto)
-    return;
+  if (fixP->fx_pcrel)
+    switch (fixP->fx_r_type)
+      {
+      case BFD_RELOC_16_PCREL_S2:
+      case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+      case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+      case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+      case BFD_RELOC_32_PCREL:
+       break;
+
+      case BFD_RELOC_32:
+       fixP->fx_r_type = BFD_RELOC_32_PCREL;
+       break;
+
+      default:
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("PC-relative reference to a different section"));
+       break;
+      }
+
+  /* Handle BFD_RELOC_8, since it's easy.  Punt on other bfd relocations
+     that have no MIPS ELF equivalent.  */
+  if (fixP->fx_r_type != BFD_RELOC_8)
+    {
+      howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+      if (!howto)
+       return;
+    }
 
   gas_assert (fixP->fx_size == 2
              || fixP->fx_size == 4
+             || fixP->fx_r_type == BFD_RELOC_8
              || fixP->fx_r_type == BFD_RELOC_16
              || fixP->fx_r_type == BFD_RELOC_64
              || fixP->fx_r_type == BFD_RELOC_CTOR
@@ -14172,12 +14365,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   buf = fixP->fx_frag->fr_literal + fixP->fx_where;
 
-  gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
-             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
-             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
-             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
-             || fixP->fx_r_type == BFD_RELOC_32_PCREL);
-
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
 
@@ -14327,6 +14514,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_32:
     case BFD_RELOC_32_PCREL:
     case BFD_RELOC_16:
+    case BFD_RELOC_8:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
         resolved when it appears but is later defined.  */
@@ -14961,6 +15149,8 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        case ISA_MIPS2:
        case ISA_MIPS32:
        case ISA_MIPS32R2:
+       case ISA_MIPS32R3:
+       case ISA_MIPS32R5:
          mips_opts.gp32 = 1;
          mips_opts.fp32 = 1;
          break;
@@ -14969,6 +15159,8 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        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)
            {
@@ -16539,11 +16731,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              switch ((insn >> 28) & 0xf)
                {
                case 4:
-                 /* bc[0-3][tf]l? instructions can have the condition
-                    reversed by tweaking a single TF bit, and their
-                    opcodes all have 0x4???????.  */
-                 gas_assert ((insn & 0xf3e00000) == 0x41000000);
-                 insn ^= 0x00010000;
+                 if ((insn & 0xff000000) == 0x47000000
+                     || (insn & 0xff600000) == 0x45600000)
+                   {
+                     /* BZ.df/BNZ.df, BZ.V/BNZ.V can have the condition
+                        reversed by tweaking bit 23.  */
+                     insn ^= 0x00800000;
+                   }
+                 else
+                   {
+                     /* bc[0-3][tf]l? instructions can have the condition
+                        reversed by tweaking a single TF bit, and their
+                        opcodes all have 0x4???????.  */
+                     gas_assert ((insn & 0xf3e00000) == 0x41000000);
+                     insn ^= 0x00010000;
+                   }
                  break;
 
                case 0:
@@ -16810,6 +17012,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                   || (insn & 0xffe30000) == 0x42800000         /* bc2f  */
                   || (insn & 0xffe30000) == 0x42a00000)        /* bc2t  */
            insn ^= 0x00200000;
+         else if ((insn & 0xff000000) == 0x83000000            /* BZ.df
+                                                                  BNZ.df  */
+                   || (insn & 0xff600000) == 0x81600000)       /* BZ.V
+                                                                  BNZ.V */
+           insn ^= 0x00800000;
          else
            abort ();
 
@@ -17211,11 +17418,9 @@ mips_elf_final_processing (void)
   if (mips_flag_nan2008)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NAN2008;
 
-#if 0 /* XXX FIXME */
   /* 32 bit code with 64 bit FP registers.  */
   if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
-    elf_elfheader (stdoutput)->e_flags |= ???;
-#endif
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_FP64;
 }
 \f
 typedef struct proc {
@@ -17665,8 +17870,12 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "mips5",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS5,    CPU_MIPS5 },
   { "mips32",         MIPS_CPU_IS_ISA, 0,      ISA_MIPS32,   CPU_MIPS32 },
   { "mips32r2",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R2, CPU_MIPS32R2 },
+  { "mips32r3",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R3, CPU_MIPS32R3 },
+  { "mips32r5",       MIPS_CPU_IS_ISA, 0,      ISA_MIPS32R5, CPU_MIPS32R5 },
   { "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 },
 
   /* MIPS I */
   { "r3000",          0, 0,                    ISA_MIPS1,    CPU_R3000 },
@@ -17769,6 +17978,8 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "1004kf2_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf",         0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "1004kf1_1",      0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
+  /* P5600 with EVA and Virtualization ASEs, other ASEs are optional.  */
+  { "p5600",          0, ASE_VIRT | ASE_EVA | ASE_XPA,         ISA_MIPS32R5, CPU_MIPS32R5 },
 
   /* MIPS 64 */
   { "5kc",            0, 0,                    ISA_MIPS64,   CPU_MIPS64 },
@@ -17781,7 +17992,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   /* Broadcom SB-1A CPU core */
   { "sb1a",           0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
   
-  { "loongson3a",     0, 0,                    ISA_MIPS64,   CPU_LOONGSON_3A },
+  { "loongson3a",     0, 0,                    ISA_MIPS64R2, CPU_LOONGSON_3A },
 
   /* MIPS 64 Release 2 */
 
@@ -17977,8 +18188,12 @@ MIPS options:\n\
 -mips5                  generate MIPS ISA V instructions\n\
 -mips32                 generate MIPS32 ISA instructions\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\
 -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\
 -march=CPU/-mtune=CPU  generate code/schedule for CPU, where CPU is one of:\n"));
 
   first = 1;
@@ -18023,6 +18238,12 @@ MIPS options:\n\
 -mmcu                  generate MCU instructions\n\
 -mno-mcu               do not generate MCU instructions\n"));
   fprintf (stream, _("\
+-mmsa                  generate MSA instructions\n\
+-mno-msa               do not generate MSA instructions\n"));
+  fprintf (stream, _("\
+-mxpa                  generate eXtended Physical Address (XPA) instructions\n\
+-mno-xpa               do not generate eXtended Physical Address (XPA) instructions\n"));
+  fprintf (stream, _("\
 -mvirt                 generate Virtualization instructions\n\
 -mno-virt              do not generate Virtualization instructions\n"));
   fprintf (stream, _("\
@@ -18123,3 +18344,34 @@ 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;
+}