]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-mips.c
Improve warning message for $0 constraint on MIPSR6 branches
[thirdparty/binutils-gdb.git] / gas / config / tc-mips.c
index 9b42ef8962d85bbbc13f59f3e74155ddc1bb7af5..f3e33410d7fa1f50866df539e18178ea82652f95 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   Copyright (C) 1993-2019 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
@@ -141,6 +141,12 @@ struct mips_cl_insn
      extension.  */
   unsigned long insn_opcode;
 
+  /* The name if this is an label.  */
+  char label[16];
+
+  /* The target label name if this is an branch.  */
+  char target[16];
+
   /* The frag that contains the instruction.  */
   struct frag *frag;
 
@@ -262,6 +268,12 @@ struct mips_set_options
   /* 1 if single-precision operations on odd-numbered registers are
      allowed.  */
   int oddspreg;
+
+  /* The set of ASEs that should be enabled for the user specified
+     architecture.  This cannot be inferred from 'arch' for all cores
+     as processors only have a unique 'arch' if they add architecture
+     specific instructions (UDI).  */
+  int init_ase;
 };
 
 /* Specifies whether module level options have been checked yet.  */
@@ -283,7 +295,8 @@ 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, /* oddspreg */ -1
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1,
+  /* init_ase */ 0
 };
 
 /* This is similar to file_mips_opts, but for the current set of options.  */
@@ -294,7 +307,8 @@ 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, /* oddspreg */ -1
+  /* soft_float */ FALSE, /* single_float */ FALSE, /* oddspreg */ -1,
+  /* init_ase */ 0
 };
 
 /* Which bits of file_ase were explicitly set or cleared by ASE options.  */
@@ -422,7 +436,9 @@ static int mips_32bitmode = 0;
     || (ISA) == ISA_MIPS64R5           \
     || (ISA) == ISA_MIPS64R6           \
     || (CPU) == CPU_R5900)             \
-   && (CPU) != CPU_LOONGSON_3A)
+   && ((CPU) != CPU_GS464              \
+    || (CPU) != CPU_GS464E             \
+    || (CPU) != CPU_GS264E))
 
 /* Return true if ISA supports move to/from high part of a 64-bit
    floating-point register. */
@@ -509,7 +525,7 @@ static int mips_32bitmode = 0;
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
-/* True if CPU is in the Octeon family */
+/* True if CPU is in the Octeon family */
 #define CPU_IS_OCTEON(CPU) ((CPU) == CPU_OCTEON || (CPU) == CPU_OCTEONP \
                            || (CPU) == CPU_OCTEON2 || (CPU) == CPU_OCTEON3)
 
@@ -658,7 +674,7 @@ static int g_switch_seen = 0;
    fixed it for the non-PIC mode.  KR 95/04/07  */
 static int nopic_need_relax (symbolS *, int);
 
-/* handle of the OPCODE hash table */
+/* Handle of the OPCODE hash table.  */
 static struct hash_control *op_hash = NULL;
 
 /* The opcode hash table we use for the mips16.  */
@@ -668,12 +684,12 @@ static struct hash_control *mips16_op_hash = NULL;
 static struct hash_control *micromips_op_hash = NULL;
 
 /* This array holds the chars that always start a comment.  If the
-    pre-processor is disabled, these aren't very useful */
+    pre-processor is disabled, these aren't very useful */
 const char comment_chars[] = "#";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
-   .line and .file directives will appear in the pre-processed output */
+   .line and .file directives will appear in the pre-processed output */
 /* Note that input_file.c hand checks for '#' at the beginning of the
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output.  */
@@ -683,22 +699,22 @@ const char line_comment_chars[] = "#";
 /* This array holds machine specific line separator characters.  */
 const char line_separator_chars[] = ";";
 
-/* Chars that can be used to separate mant from exp in floating point nums */
+/* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
 
-/* Chars that mean this number is a floating point constant */
-/* As in 0f12.456 */
-/* or    0d1.2345e12 */
+/* Chars that mean this number is a floating point constant.
+   As in 0f12.456
+   or    0d1.2345e12.  */
 const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c .  Ideally it shouldn't have to know about it at all,
-   but nothing is ideal around here.
- */
+   but nothing is ideal around here.  */
 
 /* Types of printf format used for instruction-related error messages.
-   "I" means int ("%d") and "S" means string ("%s"). */
-enum mips_insn_error_format {
+   "I" means int ("%d") and "S" means string ("%s").  */
+enum mips_insn_error_format
+{
   ERR_FMT_PLAIN,
   ERR_FMT_I,
   ERR_FMT_SS,
@@ -706,7 +722,8 @@ enum mips_insn_error_format {
 
 /* Information about an error that was found while assembling the current
    instruction.  */
-struct mips_insn_error {
+struct mips_insn_error
+{
   /* We sometimes need to match an instruction against more than one
      opcode table entry.  Errors found during this matching are reported
      against a particular syntactic argument rather than against the
@@ -725,7 +742,8 @@ struct mips_insn_error {
   /* The printf()-style message, including its format and arguments.  */
   enum mips_insn_error_format format;
   const char *msg;
-  union {
+  union
+  {
     int i;
     const char *ss[2];
   } u;
@@ -784,16 +802,20 @@ static int mips_debug = 0;
 /* The maximum number of NOPs needed for any purpose.  */
 #define MAX_NOPS 4
 
+/* The maximum range of context length of ll/sc.  */
+#define MAX_LLSC_RANGE 20
+
 /* A list of previous instructions, with index 0 being the most recent.
    We need to look back MAX_NOPS instructions when filling delay slots
    or working around processor errata.  We need to look back one
    instruction further if we're thinking about using history[0] to
    fill a branch delay slot.  */
-static struct mips_cl_insn history[1 + MAX_NOPS];
+static struct mips_cl_insn history[1 + MAX_NOPS + MAX_LLSC_RANGE];
 
 /* Arrays of operands for each instruction.  */
 #define MAX_OPERANDS 6
-struct mips_operand_array {
+struct mips_operand_array
+{
   const struct mips_operand *operand[MAX_OPERANDS];
 };
 static struct mips_operand_array *mips_operands;
@@ -806,6 +828,9 @@ static struct mips_cl_insn mips16_nop_insn;
 static struct mips_cl_insn micromips_nop16_insn;
 static struct mips_cl_insn micromips_nop32_insn;
 
+/* Sync instructions used by insert sync.  */
+static struct mips_cl_insn sync_insn;
+
 /* The appropriate nop for the current mode.  */
 #define NOP_INSN (mips_opts.mips16                                     \
                  ? &mips16_nop_insn                                    \
@@ -937,6 +962,13 @@ static int mips_fix_rm7000;
 /* ...likewise -mfix-cn63xxp1 */
 static bfd_boolean mips_fix_cn63xxp1;
 
+/* ...likewise -mfix-r5900 */
+static bfd_boolean mips_fix_r5900;
+static bfd_boolean mips_fix_r5900_explicit;
+
+/* ...likewise -mfix-loongson3-llsc.  */
+static bfd_boolean mips_fix_loongson3_llsc = DEFAULT_MIPS_FIX_LOONGSON3_LLSC;
+
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
    fail to compute the offset before expanding the macro to the most
@@ -1460,7 +1492,8 @@ enum options
     OPTION_NO_MCU,
     OPTION_MIPS16E2,
     OPTION_NO_MIPS16E2,
-    OPTION_COMPAT_ARCH_BASE,
+    OPTION_CRC,
+    OPTION_NO_CRC,
     OPTION_M4650,
     OPTION_NO_M4650,
     OPTION_M4010,
@@ -1475,6 +1508,8 @@ enum options
     OPTION_NO_FIX_24K,
     OPTION_FIX_RM7000,
     OPTION_NO_FIX_RM7000,
+    OPTION_FIX_LOONGSON3_LLSC,
+    OPTION_NO_FIX_LOONGSON3_LLSC,
     OPTION_FIX_LOONGSON2F_JUMP,
     OPTION_NO_FIX_LOONGSON2F_JUMP,
     OPTION_FIX_LOONGSON2F_NOP,
@@ -1485,6 +1520,8 @@ enum options
     OPTION_NO_FIX_VR4130,
     OPTION_FIX_CN63XXP1,
     OPTION_NO_FIX_CN63XXP1,
+    OPTION_FIX_R5900,
+    OPTION_NO_FIX_R5900,
     OPTION_TRAP,
     OPTION_BREAK,
     OPTION_EB,
@@ -1526,6 +1563,16 @@ enum options
     OPTION_NAN,
     OPTION_ODD_SPREG,
     OPTION_NO_ODD_SPREG,
+    OPTION_GINV,
+    OPTION_NO_GINV,
+    OPTION_LOONGSON_MMI,
+    OPTION_NO_LOONGSON_MMI,
+    OPTION_LOONGSON_CAM,
+    OPTION_NO_LOONGSON_CAM,
+    OPTION_LOONGSON_EXT,
+    OPTION_NO_LOONGSON_EXT,
+    OPTION_LOONGSON_EXT2,
+    OPTION_NO_LOONGSON_EXT2,
     OPTION_END_OF_ENUM
   };
 
@@ -1582,6 +1629,18 @@ struct option md_longopts[] =
   {"mno-xpa", no_argument, NULL, OPTION_NO_XPA},
   {"mmips16e2", no_argument, NULL, OPTION_MIPS16E2},
   {"mno-mips16e2", no_argument, NULL, OPTION_NO_MIPS16E2},
+  {"mcrc", no_argument, NULL, OPTION_CRC},
+  {"mno-crc", no_argument, NULL, OPTION_NO_CRC},
+  {"mginv", no_argument, NULL, OPTION_GINV},
+  {"mno-ginv", no_argument, NULL, OPTION_NO_GINV},
+  {"mloongson-mmi", no_argument, NULL, OPTION_LOONGSON_MMI},
+  {"mno-loongson-mmi", no_argument, NULL, OPTION_NO_LOONGSON_MMI},
+  {"mloongson-cam", no_argument, NULL, OPTION_LOONGSON_CAM},
+  {"mno-loongson-cam", no_argument, NULL, OPTION_NO_LOONGSON_CAM},
+  {"mloongson-ext", no_argument, NULL, OPTION_LOONGSON_EXT},
+  {"mno-loongson-ext", no_argument, NULL, OPTION_NO_LOONGSON_EXT},
+  {"mloongson-ext2", no_argument, NULL, OPTION_LOONGSON_EXT2},
+  {"mno-loongson-ext2", no_argument, NULL, OPTION_NO_LOONGSON_EXT2},
 
   /* Old-style architecture options.  Don't add more of these.  */
   {"m4650", no_argument, NULL, OPTION_M4650},
@@ -1597,6 +1656,8 @@ struct option md_longopts[] =
   {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
   {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
   {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+  {"mfix-loongson3-llsc",   no_argument, NULL, OPTION_FIX_LOONGSON3_LLSC},
+  {"mno-fix-loongson3-llsc", no_argument, NULL, OPTION_NO_FIX_LOONGSON3_LLSC},
   {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
   {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
   {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
@@ -1611,6 +1672,8 @@ struct option md_longopts[] =
   {"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},
+  {"mfix-r5900", no_argument, NULL, OPTION_FIX_R5900},
+  {"mno-fix-r5900", no_argument, NULL, OPTION_NO_FIX_R5900},
 
   /* Miscellaneous options.  */
   {"trap", no_argument, NULL, OPTION_TRAP},
@@ -1762,13 +1825,43 @@ static const struct mips_ase mips_ases[] = {
 
   { "xpa", ASE_XPA, 0,
     OPTION_XPA, OPTION_NO_XPA,
-     2,  2, -1, -1,
+    2, 2, 2, 2,
     -1 },
 
   { "mips16e2", ASE_MIPS16E2, 0,
     OPTION_MIPS16E2, OPTION_NO_MIPS16E2,
     2,  2, -1, -1,
     6 },
+
+  { "crc", ASE_CRC, ASE_CRC64,
+    OPTION_CRC, OPTION_NO_CRC,
+    6,  6, -1, -1,
+    -1 },
+
+  { "ginv", ASE_GINV, 0,
+    OPTION_GINV, OPTION_NO_GINV,
+    6,  6, 6, 6,
+    -1 },
+
+  { "loongson-mmi", ASE_LOONGSON_MMI, 0,
+    OPTION_LOONGSON_MMI, OPTION_NO_LOONGSON_MMI,
+    0, 0, -1, -1,
+    -1 },
+
+  { "loongson-cam", ASE_LOONGSON_CAM, 0,
+    OPTION_LOONGSON_CAM, OPTION_NO_LOONGSON_CAM,
+    0, 0, -1, -1,
+    -1 },
+
+  { "loongson-ext", ASE_LOONGSON_EXT, 0,
+    OPTION_LOONGSON_EXT, OPTION_NO_LOONGSON_EXT,
+    0, 0, -1, -1,
+    -1 },
+
+  { "loongson-ext2", ASE_LOONGSON_EXT | ASE_LOONGSON_EXT2, 0,
+    OPTION_LOONGSON_EXT2, OPTION_NO_LOONGSON_EXT2,
+    0, 0, -1, -1,
+    -1 },
 };
 
 /* The set of ASEs that require -mfp64.  */
@@ -1776,7 +1869,8 @@ static const struct mips_ase mips_ases[] = {
 
 /* Groups of ASE_* flags that represent different revisions of an ASE.  */
 static const unsigned int mips_ase_groups[] = {
-  ASE_DSP | ASE_DSPR2 | ASE_DSPR3
+  ASE_DSP | ASE_DSPR2 | ASE_DSPR3, 
+  ASE_LOONGSON_EXT | ASE_LOONGSON_EXT2 
 };
 \f
 /* Pseudo-op table.
@@ -2710,7 +2804,7 @@ struct regname {
     {"$ta2",   RTYPE_GP | 14}, /* alias for $t6 */ \
     {"$ta3",   RTYPE_GP | 15}  /* alias for $t7 */
 
-/* Remaining symbolic register names */
+/* Remaining symbolic register names */
 #define SYMBOLIC_REGISTER_NAMES \
     {"$zero",  RTYPE_GP | 0},  \
     {"$at",    RTYPE_GP | 1},  \
@@ -2745,8 +2839,8 @@ struct regname {
     {"$pc",    RTYPE_PC | 0}
 
 #define MDMX_VECTOR_REGISTER_NAMES \
-    /* {"$v0", RTYPE_VEC | 0},  clash with REG 2 above */ \
-    /* {"$v1", RTYPE_VEC | 1},  clash with REG 3 above */ \
+    /* {"$v0", RTYPE_VEC | 0},  Clash with REG 2 above.  */ \
+    /* {"$v1", RTYPE_VEC | 1},  Clash with REG 3 above.  */ \
     {"$v2",    RTYPE_VEC | 2},  \
     {"$v3",    RTYPE_VEC | 3},  \
     {"$v4",    RTYPE_VEC | 4},  \
@@ -3607,6 +3701,7 @@ md_begin (void)
          if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
                                   decode_mips_operand, &mips_operands[i]))
            broken = 1;
+
          if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
            {
              create_insn (&nop_insn, mips_opcodes + i);
@@ -3614,6 +3709,10 @@ md_begin (void)
                nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
              nop_insn.fixed_p = 1;
            }
+
+          if (sync_insn.insn_mo == NULL && strcmp (name, "sync") == 0)
+           create_insn (&sync_insn, mips_opcodes + i);
+
          ++i;
        }
       while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
@@ -3769,7 +3868,7 @@ md_begin (void)
 
     /* The ABI says this section should be loaded so that the
        running program can access it.  However, we don't load it
-       if we are configured for an embedded target */
+       if we are configured for an embedded target */
     flags = SEC_READONLY | SEC_DATA;
     if (strncmp (TARGET_OS, "elf", 3) != 0)
       flags |= SEC_ALLOC | SEC_LOAD;
@@ -3995,8 +4094,6 @@ mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks)
 static void
 file_mips_check_options (void)
 {
-  const struct mips_cpu_info *arch_info = 0;
-
   if (file_mips_opts_checked)
     return;
 
@@ -4039,8 +4136,6 @@ file_mips_check_options (void)
        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)
@@ -4084,7 +4179,7 @@ file_mips_check_options (void)
 
   /* 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);
+  file_mips_opts.ase |= (file_mips_opts.init_ase & ~file_ase_explicit);
 
   /* Set up the current options.  These may change throughout assembly.  */
   mips_opts = file_mips_opts;
@@ -4897,7 +4992,7 @@ match_expression (struct mips_arg_info *arg, expressionS *value,
 }
 
 /* Try to get a constant expression from the next tokens in ARG.  Consume
-   the tokens and return return true on success, storing the constant value
+   the tokens and return true on success, storing the constant value
    in *VALUE.  */
 
 static bfd_boolean
@@ -5919,7 +6014,10 @@ match_non_zero_reg_operand (struct mips_arg_info *arg,
     return FALSE;
 
   if (regno == 0)
-    return FALSE;
+    {
+      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);
@@ -5937,9 +6035,9 @@ match_tied_reg_operand (struct mips_arg_info *arg, unsigned int other_regno)
   return match_reg (arg, OP_REG_GP, &regno) && regno == other_regno;
 }
 
-/* Read a floating-point constant from S for LI.S or LI.D.  LENGTH is
-   the length of the value in bytes (4 for float, 8 for double) and
-   USING_GPRS says whether the destination is a GPR rather than an FPR.
+/* Try to match a floating-point constant from ARG for LI.S or LI.D.
+   LENGTH is the length of the value in bytes (4 for float, 8 for double)
+   and USING_GPRS says whether the destination is a GPR rather than an FPR.
 
    Return the constant in IMM and OFFSET as follows:
 
@@ -6133,8 +6231,8 @@ match_vu0_suffix_operand (struct mips_arg_info *arg,
   return TRUE;
 }
 
-/* S is the text seen for ARG.  Match it against OPERAND.  Return the end
-   of the argument text if the match is successful, otherwise return null.  */
+/* Try to match a token from ARG against OPERAND.  Consume the token
+   and return true on success, otherwise return false.  */
 
 static bfd_boolean
 match_operand (struct mips_arg_info *arg,
@@ -6795,6 +6893,103 @@ fix_loongson2f (struct mips_cl_insn * ip)
     fix_loongson2f_jump (ip);
 }
 
+/* Fix loongson3 llsc errata: Insert sync before ll/lld. */
+
+static void
+fix_loongson3_llsc (struct mips_cl_insn * ip)
+{
+  gas_assert (!HAVE_CODE_COMPRESSION);
+
+  /* If is an local label and the insn is not sync,
+     look forward that whether an branch between ll/sc jump to here
+     if so, insert a sync.  */
+  if (seg_info (now_seg)->label_list
+      && S_IS_LOCAL (seg_info (now_seg)->label_list->label)
+      && (strcmp (ip->insn_mo->name, "sync") != 0))
+    {
+      const char *label_name = S_GET_NAME (seg_info (now_seg)->label_list->label);
+      unsigned long lookback = ARRAY_SIZE (history);
+      unsigned long i;
+
+      for (i = 0; i < lookback; i++)
+       {
+         if (streq (history[i].insn_mo->name, "ll")
+             || streq (history[i].insn_mo->name, "lld"))
+           break;
+
+         if (streq (history[i].insn_mo->name, "sc")
+             || streq (history[i].insn_mo->name, "scd"))
+           {
+             unsigned long j;
+
+             for (j = i + 1; j < lookback; j++)
+               {
+                 if (streq (history[i].insn_mo->name, "ll")
+                     || streq (history[i].insn_mo->name, "lld"))
+                   break;
+
+                 if (delayed_branch_p (&history[j]))
+                   {
+                     if (streq (history[j].target, label_name))
+                       {
+                         add_fixed_insn (&sync_insn);
+                         insert_into_history (0, 1, &sync_insn);
+                         i = lookback;
+                         break;
+                       }
+                   }
+               }
+           }
+       }
+    }
+  /* If we find a sc, we look forward to look for an branch insn,
+     and see whether it jump back and out of ll/sc.  */
+  else if (streq(ip->insn_mo->name, "sc") || streq(ip->insn_mo->name, "scd"))
+    {
+      unsigned long lookback = ARRAY_SIZE (history) - 1;
+      unsigned long i;
+
+      for (i = 0; i < lookback; i++)
+       {
+         if (streq (history[i].insn_mo->name, "ll")
+             || streq (history[i].insn_mo->name, "lld"))
+           break;
+
+         if (delayed_branch_p (&history[i]))
+           {
+             unsigned long j;
+
+             for (j = i + 1; j < lookback; j++)
+               {
+                 if (streq (history[j].insn_mo->name, "ll")
+                     || streq (history[i].insn_mo->name, "lld"))
+                   break;
+               }
+
+             for (; j < lookback; j++)
+               {
+                 if (history[j].label[0] != '\0'
+                     && streq (history[j].label, history[i].target)
+                     && strcmp (history[j+1].insn_mo->name, "sync") != 0)
+                   {
+                     add_fixed_insn (&sync_insn);
+                     insert_into_history (++j, 1, &sync_insn);
+                   }
+               }
+           }
+       }
+    }
+
+  /* Skip if there is a sync before ll/lld.  */
+  if ((strcmp (ip->insn_mo->name, "ll") == 0
+       || strcmp (ip->insn_mo->name, "lld") == 0)
+      && (strcmp (history[0].insn_mo->name, "sync") != 0))
+    {
+      add_fixed_insn (&sync_insn);
+      insert_into_history (0, 1, &sync_insn);
+    }
+}
+
 /* IP is a branch that has a delay slot, and we need to fill it
    automatically.   Return true if we can do that by swapping IP
    with the previous instruction.
@@ -6926,10 +7121,22 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
       && insn_length (history) != 4)
     return FALSE;
 
-  /* On R5900 short loops need to be fixed by inserting a nop in
-     the branch delay slots.
-     A short loop can be terminated too early.  */
-  if (mips_opts.arch == CPU_R5900
+  /* On the R5900 short loops need to be fixed by inserting a NOP in the
+     branch delay slot.
+
+     The short loop bug under certain conditions causes loops to execute
+     only once or twice.  We must ensure that the assembler never
+     generates loops that satisfy all of the following conditions:
+
+     - a loop consists of less than or equal to six instructions
+       (including the branch delay slot);
+     - a loop contains only one conditional branch instruction at the end
+       of the loop;
+     - a loop does not contain any other branch or jump instructions;
+     - a branch delay slot of the loop is not NOP (EE 2.9 or later).
+
+     We need to do this because of a hardware bug in the R5900 chip.  */
+  if (mips_fix_r5900
       /* Check if instruction has a parameter, ignore "j $31". */
       && (address_expr != NULL)
       /* Parameter must be 16 bit. */
@@ -6946,8 +7153,8 @@ can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
        || (ip->insn_opcode & 0xffff0000) == 0x04110000)) /* bgezal $0 */
     {
       int distance;
-      /* Check if loop is shorter than 6 instructions including
-         branch and delay slot.  */
+      /* Check if loop is shorter than or equal to 6 instructions
+         including branch and delay slot.  */
       distance = frag_now_fix () - S_GET_VALUE (address_expr->X_add_symbol);
       if (distance <= 20)
         {
@@ -7240,6 +7447,15 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
+  ip->target[0] = '\0';
+  if (offset_expr.X_op == O_symbol)
+    strncpy (ip->target, S_GET_NAME (offset_expr.X_add_symbol), 15);
+  ip->label[0] = '\0';
+  if (seg_info (now_seg)->label_list)
+    strncpy (ip->label, S_GET_NAME (seg_info (now_seg)->label_list->label), 15);
+  if (mips_fix_loongson3_llsc && !HAVE_CODE_COMPRESSION)
+    fix_loongson3_llsc (ip);
+
   file_ase_mips16 |= mips_opts.mips16;
   file_ase_micromips |= mips_opts.micromips;
 
@@ -8834,7 +9050,26 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
                      || *r == BFD_RELOC_MIPS_HIGHER
                      || *r == BFD_RELOC_HI16_S
                      || *r == BFD_RELOC_LO16
-                     || *r == BFD_RELOC_MIPS_GOT_OFST);
+                     || *r == BFD_RELOC_MIPS_GOT_OFST
+                     || (mips_opts.micromips
+                         && (*r == BFD_RELOC_16
+                             || *r == BFD_RELOC_MIPS_GOT16
+                             || *r == BFD_RELOC_MIPS_CALL16
+                             || *r == BFD_RELOC_MIPS_GOT_HI16
+                             || *r == BFD_RELOC_MIPS_GOT_LO16
+                             || *r == BFD_RELOC_MIPS_CALL_HI16
+                             || *r == BFD_RELOC_MIPS_CALL_LO16
+                             || *r == BFD_RELOC_MIPS_SUB
+                             || *r == BFD_RELOC_MIPS_GOT_PAGE
+                             || *r == BFD_RELOC_MIPS_HIGHEST
+                             || *r == BFD_RELOC_MIPS_GOT_DISP
+                             || *r == BFD_RELOC_MIPS_TLS_GD
+                             || *r == BFD_RELOC_MIPS_TLS_LDM
+                             || *r == BFD_RELOC_MIPS_TLS_DTPREL_HI16
+                             || *r == BFD_RELOC_MIPS_TLS_DTPREL_LO16
+                             || *r == BFD_RELOC_MIPS_TLS_GOTTPREL
+                             || *r == BFD_RELOC_MIPS_TLS_TPREL_HI16
+                             || *r == BFD_RELOC_MIPS_TLS_TPREL_LO16)));
          break;
 
        case 'o':
@@ -10266,7 +10501,7 @@ macro (struct mips_cl_insn *ip, char *str)
          break;
        }
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BGE_I:
     case M_BGEL_I:
       if (mask == M_BGEL_I)
@@ -10286,7 +10521,7 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm_expr.X_add_number <= GPR_SMIN)
        {
        do_true:
-         /* result is always true */
+         /* Result is always true.  */
          as_warn (_("branch %s is always true"), ip->insn_mo->name);
          macro_build (&offset_expr, "b", "p");
          break;
@@ -10324,7 +10559,7 @@ macro (struct mips_cl_insn *ip, char *str)
              && imm_expr.X_add_number == -1))
        goto do_false;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BGEU_I:
     case M_BGEUL_I:
       if (mask == M_BGEUL_I)
@@ -10402,7 +10637,7 @@ macro (struct mips_cl_insn *ip, char *str)
       if (imm_expr.X_add_number >= GPR_SMAX)
        goto do_true;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BLT_I:
     case M_BLTL_I:
       if (mask == M_BLTL_I)
@@ -10447,7 +10682,7 @@ macro (struct mips_cl_insn *ip, char *str)
              && imm_expr.X_add_number == -1))
        goto do_true;
       ++imm_expr.X_add_number;
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case M_BLTU_I:
     case M_BLTUL_I:
       if (mask == M_BLTUL_I)
@@ -12538,20 +12773,18 @@ macro (struct mips_cl_insn *ip, char *str)
          offset_reloc[2] = BFD_RELOC_UNUSED;
        }
       align = 8;
-      /* Fall through */
+      /* Fall through */
 
     case M_L_DAB:
-      /*
-       * The MIPS assembler seems to check for X_add_number not
-       * being double aligned and generating:
-       *       lui     at,%hi(foo+1)
-       *       addu    at,at,v1
-       *       addiu   at,at,%lo(foo+1)
-       *       lwc1    f2,0(at)
-       *       lwc1    f3,4(at)
-       * But, the resulting address is the same after relocation so why
-       * generate the extra instruction?
-       */
+      /* The MIPS assembler seems to check for X_add_number not
+         being double aligned and generating:
+               lui     at,%hi(foo+1)
+               addu    at,at,v1
+               addiu   at,at,%lo(foo+1)
+               lwc1    f2,0(at)
+               lwc1    f3,4(at)
+         But, the resulting address is the same after relocation so why
+         generate the extra instruction?  */
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
@@ -13274,7 +13507,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGE_I:      /* X >= I  <==>  not (X < I) */
+    case M_SGE_I:      /* X >= I  <==>  not (X < I) */
     case M_SGEU_I:
       if (imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
@@ -13290,7 +13523,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (&expr1, "xori", "t,r,i", op[0], op[0], BFD_RELOC_LO16);
       break;
 
-    case M_SGT:                /* X > Y  <==>  Y < X */
+    case M_SGT:                /* X > Y  <==>  Y < X */
       s = "slt";
       goto sgt;
     case M_SGTU:
@@ -13299,7 +13532,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (NULL, s, "d,v,t", op[0], op[2], op[1]);
       break;
 
-    case M_SGT_I:      /* X > I  <==>  I < X */
+    case M_SGT_I:      /* X > I  <==>  I < X */
       s = "slt";
       goto sgti;
     case M_SGTU_I:
@@ -13310,7 +13543,7 @@ macro (struct mips_cl_insn *ip, char *str)
       macro_build (NULL, s, "d,v,t", op[0], AT, op[1]);
       break;
 
-    case M_SLE:                /* X <= Y  <==>  Y >= X  <==>  not (Y < X) */
+    case M_SLE:                /* X <= Y  <==>  Y >= X  <==>  not (Y < X) */
       s = "slt";
       goto sle;
     case M_SLEU:
@@ -13956,7 +14189,7 @@ mips_lookup_insn (struct hash_control *hash, const char *start,
        suffix = 0;
       if (suffix)
        {
-         memcpy (name + opend - 2, name + opend, length - opend + 1);
+         memmove (name + opend - 2, name + opend, length - opend + 1);
          insn = (struct mips_opcode *) hash_find (hash, name);
          if (insn)
            {
@@ -14636,6 +14869,14 @@ md_parse_option (int c, const char *arg)
       mips_fix_rm7000 = 0;
       break;
 
+    case OPTION_FIX_LOONGSON3_LLSC:
+      mips_fix_loongson3_llsc = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON3_LLSC:
+      mips_fix_loongson3_llsc = FALSE;
+      break;
+
     case OPTION_FIX_LOONGSON2F_JUMP:
       mips_fix_loongson2f_jump = TRUE;
       break;
@@ -14676,6 +14917,16 @@ md_parse_option (int c, const char *arg)
       mips_fix_cn63xxp1 = FALSE;
       break;
 
+    case OPTION_FIX_R5900:
+      mips_fix_r5900 = TRUE;
+      mips_fix_r5900_explicit = TRUE;
+      break;
+
+    case OPTION_NO_FIX_R5900:
+      mips_fix_r5900 = FALSE;
+      mips_fix_r5900_explicit = TRUE;
+      break;
+
     case OPTION_RELAX_BRANCH:
       mips_relax_branch = 1;
       break;
@@ -14894,7 +15145,7 @@ mips_after_parse_args (void)
   const struct mips_cpu_info *arch_info = 0;
   const struct mips_cpu_info *tune_info = 0;
 
-  /* GP relative stuff not working for PE */
+  /* GP relative stuff not working for PE */
   if (strncmp (TARGET_OS, "pe", 2) == 0)
     {
       if (g_switch_seen && g_switch_value != 0)
@@ -14945,10 +15196,15 @@ mips_after_parse_args (void)
 
   file_mips_opts.arch = arch_info->cpu;
   file_mips_opts.isa = arch_info->isa;
+  file_mips_opts.init_ase = arch_info->ase;
 
   /* Set up initial mips_opts state.  */
   mips_opts = file_mips_opts;
 
+  /* For the R5900 default to `-mfix-r5900' unless the user told otherwise.  */
+  if (!mips_fix_r5900_explicit)
+    mips_fix_r5900 = file_mips_opts.arch == CPU_R5900;
+
   /* The register size inference code is now placed in
      file_mips_check_options.  */
 
@@ -14969,7 +15225,7 @@ mips_after_parse_args (void)
 void
 mips_init_after_args (void)
 {
-  /* initialize opcodes */
+  /* Initialize opcodes.  */
   bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
   mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
 }
@@ -14978,6 +15234,7 @@ long
 md_pcrel_from (fixS *fixP)
 {
   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
+
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_MICROMIPS_7_PCREL_S1:
@@ -15314,7 +15571,7 @@ fix_bad_misaligned_jump_p (fixS *fixP, int shift)
    We accept BFD_RELOC_16_PCREL_S2 relocations against MIPS16 and microMIPS
    symbols or BFD_RELOC_MICROMIPS_16_PCREL_S1 relocations against regular
    MIPS symbols and associated with BAL instructions as these instructions
-   may be be converted to JALX by the linker.  */
+   may be converted to JALX by the linker.  */
 
 static bfd_boolean
 fix_bad_cross_mode_branch_p (fixS *fixP)
@@ -16310,6 +16567,7 @@ parse_code_option (char * name)
              mips_opts.arch = p->cpu;
              mips_opts.isa = p->isa;
              isa_set = TRUE;
+             mips_opts.init_ase = p->ase;
            }
        }
       else if (strncmp (name, "mips", 4) == 0)
@@ -16324,6 +16582,7 @@ parse_code_option (char * name)
              mips_opts.arch = p->cpu;
              mips_opts.isa = p->isa;
              isa_set = TRUE;
+             mips_opts.init_ase = p->ase;
            }
        }
       else
@@ -16397,6 +16656,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     {
       mips_opts.isa = file_mips_opts.isa;
       mips_opts.arch = file_mips_opts.arch;
+      mips_opts.init_ase = file_mips_opts.init_ase;
       mips_opts.gp = file_mips_opts.gp;
       mips_opts.fp = file_mips_opts.fp;
     }
@@ -17149,6 +17409,7 @@ s_nan (int ignore ATTRIBUTE_UNUSED)
 static void
 s_mips_stab (int type)
 {
+  file_mips_check_options ();
   mips_mark_labels ();
   s_stab (type);
 }
@@ -18135,7 +18396,6 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
     {
       char *buf;
       unsigned long insn;
-      expressionS exp;
       fixS *fixp;
 
       buf = fragp->fr_literal + fragp->fr_fix;
@@ -18146,12 +18406,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* We generate a fixup instead of applying it right now
             because, if there are linker relaxations, we're going to
             need the relocations.  */
-         exp.X_op = O_symbol;
-         exp.X_add_symbol = fragp->fr_symbol;
-         exp.X_add_number = fragp->fr_offset;
-
-         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
-                             BFD_RELOC_16_PCREL_S2);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                         fragp->fr_symbol, fragp->fr_offset,
+                         TRUE, BFD_RELOC_16_PCREL_S2);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -18267,12 +18524,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              /* j or jal.  */
              insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
                      ? 0x0c000000 : 0x08000000);
-             exp.X_op = O_symbol;
-             exp.X_add_symbol = fragp->fr_symbol;
-             exp.X_add_number = fragp->fr_offset;
 
-             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
-                                 FALSE, BFD_RELOC_MIPS_JMP);
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             FALSE, BFD_RELOC_MIPS_JMP);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -18285,18 +18540,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              /* lw/ld $at, <sym>($gp)  R_MIPS_GOT16 */
              insn = HAVE_64BIT_ADDRESSES ? 0xdf800000 : 0x8f800000;
              insn |= at << OP_SH_RT;
-             exp.X_op = O_symbol;
-             exp.X_add_symbol = fragp->fr_symbol;
-             exp.X_add_number = fragp->fr_offset;
 
-             if (fragp->fr_offset)
-               {
-                 exp.X_add_symbol = make_expr_symbol (&exp);
-                 exp.X_add_number = 0;
-               }
-
-             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
-                                 FALSE, BFD_RELOC_MIPS_GOT16);
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             FALSE, BFD_RELOC_MIPS_GOT16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -18310,8 +18557,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              insn = HAVE_64BIT_ADDRESSES ? 0x64000000 : 0x24000000;
              insn |= at << OP_SH_RS | at << OP_SH_RT;
 
-             fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
-                                 FALSE, BFD_RELOC_LO16);
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             FALSE, BFD_RELOC_LO16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -18345,13 +18593,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
       bfd_boolean short_ds;
       unsigned long insn;
-      expressionS exp;
       fixS *fixp;
 
-      exp.X_op = O_symbol;
-      exp.X_add_symbol = fragp->fr_symbol;
-      exp.X_add_number = fragp->fr_offset;
-
       fragp->fr_fix += fragp->fr_var;
 
       /* Handle 16-bit branches that fit or are forced to fit.  */
@@ -18360,14 +18603,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* We generate a fixup instead of applying it right now,
             because if there is linker relaxation, we're going to
             need the relocations.  */
-         if (type == 'D')
-           fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
-                               BFD_RELOC_MICROMIPS_10_PCREL_S1);
-         else if (type == 'E')
-           fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 2, &exp, TRUE,
-                               BFD_RELOC_MICROMIPS_7_PCREL_S1);
-         else
-           abort ();
+         switch (type)
+           {
+           case 'D':
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 2,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             TRUE, BFD_RELOC_MICROMIPS_10_PCREL_S1);
+             break;
+           case 'E':
+             fixp = fix_new (fragp, buf - fragp->fr_literal, 2,
+                             fragp->fr_symbol, fragp->fr_offset,
+                             TRUE, BFD_RELOC_MICROMIPS_7_PCREL_S1);
+             break;
+           default:
+             abort ();
+           }
 
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
@@ -18386,8 +18636,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* We generate a fixup instead of applying it right now,
             because if there is linker relaxation, we're going to
             need the relocations.  */
-         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, TRUE,
-                             BFD_RELOC_MICROMIPS_16_PCREL_S1);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                         fragp->fr_symbol, fragp->fr_offset,
+                         TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -18524,8 +18775,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          /* j/jal/jals <sym>  R_MICROMIPS_26_S1  */
          insn = al ? jal : 0xd4000000;
 
-         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
-                             BFD_RELOC_MICROMIPS_JMP);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                         fragp->fr_symbol, fragp->fr_offset,
+                         FALSE, BFD_RELOC_MICROMIPS_JMP);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -18548,14 +18800,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
          insn |= at << MICROMIPSOP_SH_RT;
 
-         if (exp.X_add_number)
-           {
-             exp.X_add_symbol = make_expr_symbol (&exp);
-             exp.X_add_number = 0;
-           }
-
-         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
-                             BFD_RELOC_MICROMIPS_GOT16);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                         fragp->fr_symbol, fragp->fr_offset,
+                         FALSE, BFD_RELOC_MICROMIPS_GOT16);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -18565,8 +18812,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          insn = HAVE_64BIT_ADDRESSES ? 0x5c000000 : 0x30000000;
          insn |= at << MICROMIPSOP_SH_RT | at << MICROMIPSOP_SH_RS;
 
-         fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp, FALSE,
-                             BFD_RELOC_MICROMIPS_LO16);
+         fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                         fragp->fr_symbol, fragp->fr_offset,
+                         FALSE, BFD_RELOC_MICROMIPS_LO16);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -18643,7 +18891,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
 
          if (pcrel_op->include_isa_bit && !need_reloc)
            {
-             if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
+             if (!mips_ignore_branch_isa
+                 && !ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
                as_bad_where (fragp->fr_file, fragp->fr_line,
                              _("branch to a symbol in another ISA mode"));
              else if ((fragp->fr_offset & 0x1) != 0)
@@ -18770,7 +19019,6 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          if (need_reloc)
            {
              bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
-             expressionS exp;
              fixS *fixp;
 
              switch (type)
@@ -18787,13 +19035,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                              _("unsupported relocation"));
              else if (ext)
                {
-                 exp.X_op = O_symbol;
-                 exp.X_add_symbol = fragp->fr_symbol;
-                 exp.X_add_number = fragp->fr_offset;
-
-                 fixp = fix_new_exp (fragp, buf - fragp->fr_literal, 4, &exp,
-                                     TRUE, reloc);
-
+                 fixp = fix_new (fragp, buf - fragp->fr_literal, 4,
+                                 fragp->fr_symbol, fragp->fr_offset,
+                                 TRUE, reloc);
                  fixp->fx_file = fragp->fr_file;
                  fixp->fx_line = fragp->fr_line;
                }
@@ -18815,7 +19059,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       relax_substateT subtype = fragp->fr_subtype;
       bfd_boolean second_longer = (subtype & RELAX_SECOND_LONGER) != 0;
       bfd_boolean use_second = (subtype & RELAX_USE_SECOND) != 0;
-      int first, second;
+      unsigned int first, second;
       fixS *fixp;
 
       first = RELAX_FIRST (subtype);
@@ -18858,7 +19102,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
         sequence instead.  */
       while (fixp
             && fixp->fx_frag == fragp
-            && fixp->fx_where < fragp->fr_fix - second)
+            && fixp->fx_where + second < fragp->fr_fix)
        {
          if (subtype & RELAX_USE_SECOND)
            fixp->fx_done = 1;
@@ -18993,6 +19237,18 @@ mips_convert_ase_flags (int ase)
     ext_ases |= AFL_ASE_XPA;
   if (ase & ASE_MIPS16E2)
     ext_ases |= file_ase_mips16 ? AFL_ASE_MIPS16E2 : 0;
+  if (ase & ASE_CRC)
+    ext_ases |= AFL_ASE_CRC;
+  if (ase & ASE_GINV)
+    ext_ases |= AFL_ASE_GINV;
+  if (ase & ASE_LOONGSON_MMI)
+    ext_ases |= AFL_ASE_LOONGSON_MMI;
+  if (ase & ASE_LOONGSON_CAM)
+    ext_ases |= AFL_ASE_LOONGSON_CAM;
+  if (ase & ASE_LOONGSON_EXT)
+    ext_ases |= AFL_ASE_LOONGSON_EXT;
+  if (ase & ASE_LOONGSON_EXT2)
+    ext_ases |= AFL_ASE_LOONGSON_EXT2;
 
   return ext_ases;
 }
@@ -19156,10 +19412,8 @@ mips_elf_final_processing (void)
       else
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
     }
-  else if (mips_abi == N32_ABI)
-    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
 
-  /* Nothing to do for N64_ABI.  */
+  /* Nothing to do for N32_ABI or N64_ABI.  */
 
   if (mips_32bitmode)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
@@ -19343,7 +19597,7 @@ s_mips_file (int x ATTRIBUTE_UNUSED)
     {
       char *filename;
 
-      filename = dwarf2_directive_file (0);
+      filename = dwarf2_directive_filename ();
 
       /* Versions of GCC up to 3.1 start files with a ".file"
         directive even for stabs output.  Make sure that this
@@ -19600,7 +19854,7 @@ s_mips_mask (int reg_type)
    gcc's mips_cpu_info_table[].  */
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
-  /* Entries for generic ISAs */
+  /* Entries for generic ISAs */
   { "mips1",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS1,    CPU_R3000 },
   { "mips2",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS2,    CPU_R6000 },
   { "mips3",          MIPS_CPU_IS_ISA, 0,      ISA_MIPS3,    CPU_R4000 },
@@ -19639,9 +19893,9 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "orion",          0, 0,                    ISA_MIPS3,    CPU_R4600 },
   { "r4650",          0, 0,                    ISA_MIPS3,    CPU_R4650 },
   { "r5900",          0, 0,                    ISA_MIPS3,    CPU_R5900 },
-  /* ST Microelectronics Loongson 2E and 2F cores */
+  /* ST Microelectronics Loongson 2E and 2F cores */
   { "loongson2e",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2E },
-  { "loongson2f",     0, 0,                    ISA_MIPS3,    CPU_LOONGSON_2F },
+  { "loongson2f",     0, ASE_LOONGSON_MMI,     ISA_MIPS3,    CPU_LOONGSON_2F },
 
   /* MIPS IV */
   { "r8000",          0, 0,                    ISA_MIPS4,    CPU_R8000 },
@@ -19718,12 +19972,12 @@ 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 },
-  /* interaptiv is the new name for 1004kf */
+  /* interaptiv is the new name for 1004kf */
   { "interaptiv",     0, ASE_DSP | ASE_MT,     ISA_MIPS32R2, CPU_MIPS32R2 },
   { "interaptiv-mr2", 0,
     ASE_DSP | ASE_EVA | ASE_MT | ASE_MIPS16E2 | ASE_MIPS16E2_MT,
     ISA_MIPS32R3, CPU_INTERAPTIV_MR2 },
-  /* M5100 family */
+  /* M5100 family */
   { "m5100",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   { "m5101",          0, ASE_MCU,              ISA_MIPS32R5, CPU_MIPS32R5 },
   /* P5600 with EVA and Virtualization ASEs, other ASEs are optional.  */
@@ -19735,16 +19989,24 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "20kc",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
   { "25kf",           0, ASE_MIPS3D,           ISA_MIPS64,   CPU_MIPS64 },
 
-  /* Broadcom SB-1 CPU core */
+  /* Broadcom SB-1 CPU core */
   { "sb1",            0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
-  /* Broadcom SB-1A CPU core */
+  /* Broadcom SB-1A CPU core */
   { "sb1a",           0, ASE_MIPS3D | ASE_MDMX,        ISA_MIPS64,   CPU_SB1 },
 
-  { "loongson3a",     0, 0,                    ISA_MIPS64R2, CPU_LOONGSON_3A },
-
-  /* MIPS 64 Release 2 */
-
-  /* Cavium Networks Octeon CPU core */
+  /* MIPS 64 Release 2.  */
+  /* Loongson CPU core.  */
+  /* -march=loongson3a is an alias of -march=gs464 for compatibility.  */
+  { "loongson3a",     0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
+     ISA_MIPS64R2,     CPU_GS464 },
+  { "gs464",          0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT,
+     ISA_MIPS64R2,     CPU_GS464 },
+  { "gs464e",         0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
+     | ASE_LOONGSON_EXT2,      ISA_MIPS64R2,   CPU_GS464E },
+  { "gs264e",         0, ASE_LOONGSON_MMI | ASE_LOONGSON_CAM | ASE_LOONGSON_EXT
+     | ASE_LOONGSON_EXT2 | ASE_MSA | ASE_MSA64,        ISA_MIPS64R2,   CPU_GS264E },
+
+  /* Cavium Networks Octeon CPU core.  */
   { "octeon",        0, 0,                     ISA_MIPS64R2, CPU_OCTEON },
   { "octeon+",       0, 0,                     ISA_MIPS64R2, CPU_OCTEONP },
   { "octeon2",       0, 0,                     ISA_MIPS64R2, CPU_OCTEON2 },
@@ -19758,11 +20020,13 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
      MIPS64R2 rather than MIPS64.  */
   { "xlp",           0, 0,                     ISA_MIPS64R2, CPU_XLR },
 
-  /* MIPS 64 Release 6 */
-  { "i6400",         0, ASE_MSA,               ISA_MIPS64R6, CPU_MIPS64R6},
+  /* MIPS 64 Release 6.  */
+  { "i6400",         0, ASE_VIRT | ASE_MSA,    ISA_MIPS64R6, CPU_MIPS64R6},
+  { "i6500",         0, ASE_VIRT | ASE_MSA | ASE_CRC | ASE_GINV,
+                                               ISA_MIPS64R6, CPU_MIPS64R6},
   { "p6600",         0, ASE_VIRT | ASE_MSA,    ISA_MIPS64R6, CPU_MIPS64R6},
 
-  /* End marker */
+  /* End marker */
   { NULL, 0, 0, 0, 0 }
 };
 
@@ -19976,6 +20240,9 @@ MIPS options:\n\
 -mips16                        generate mips16 instructions\n\
 -no-mips16             do not generate mips16 instructions\n"));
   fprintf (stream, _("\
+-mmips16e2             generate MIPS16e2 instructions\n\
+-mno-mips16e2          do not generate MIPS16e2 instructions\n"));
+  fprintf (stream, _("\
 -mmicromips            generate microMIPS instructions\n\
 -mno-micromips         do not generate microMIPS instructions\n"));
   fprintf (stream, _("\
@@ -20006,20 +20273,51 @@ MIPS options:\n\
 -mvirt                 generate Virtualization instructions\n\
 -mno-virt              do not generate Virtualization instructions\n"));
   fprintf (stream, _("\
+-mcrc                  generate CRC instructions\n\
+-mno-crc               do not generate CRC instructions\n"));
+  fprintf (stream, _("\
+-mginv                 generate Global INValidate (GINV) instructions\n\
+-mno-ginv              do not generate Global INValidate instructions\n"));
+  fprintf (stream, _("\
+-mloongson-mmi         generate Loongson MultiMedia extensions Instructions (MMI) instructions\n\
+-mno-loongson-mmi      do not generate Loongson MultiMedia extensions Instructions\n"));
+  fprintf (stream, _("\
+-mloongson-cam         generate Loongson Content Address Memory (CAM) instructions\n\
+-mno-loongson-cam      do not generate Loongson Content Address Memory Instructions\n"));
+  fprintf (stream, _("\
+-mloongson-ext         generate Loongson EXTensions (EXT) instructions\n\
+-mno-loongson-ext      do not generate Loongson EXTensions Instructions\n"));
+  fprintf (stream, _("\
+-mloongson-ext2                generate Loongson EXTensions R2 (EXT2) instructions\n\
+-mno-loongson-ext2     do not generate Loongson EXTensions R2 Instructions\n"));
+  fprintf (stream, _("\
 -minsn32               only generate 32-bit microMIPS instructions\n\
 -mno-insn32            generate all microMIPS instructions\n"));
+#if DEFAULT_MIPS_FIX_LOONGSON3_LLSC
+  fprintf (stream, _("\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata, default\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata\n"));
+#else
+  fprintf (stream, _("\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata, default\n"));
+#endif
   fprintf (stream, _("\
 -mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
 -mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
+-mfix-loongson3-llsc   work around Loongson3 LL/SC errata\n\
+-mno-fix-loongson3-llsc        disable work around Loongson3 LL/SC errata\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mfix-24k              insert a nop after ERET and DERET instructions\n\
 -mfix-cn63xxp1         work around CN63XXP1 PREF errata\n\
+-mfix-r5900            work around R5900 short loop errata\n\
 -mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
 -mfp32                 use 32-bit FPRs, regardless of the chosen ISA\n\
 -msym32                        assume all symbols have 32-bit values\n\
--O0                    remove unneeded NOPs, do not swap branches\n\
--O                     remove unneeded NOPs and swap branches\n\
+-O0                    do not remove unneeded NOPs, do not swap branches\n\
+-O, -O1                        remove unneeded NOPs, do not swap branches\n\
+-O2                    remove unneeded NOPs and swap branches\n\
 --trap, --no-break     trap exception on div by 0 and mult overflow\n\
 --break, --no-trap     break exception on div by 0 and mult overflow\n"));
   fprintf (stream, _("\
@@ -20062,9 +20360,14 @@ MIPS options:\n\
   fputc ('\n', stream);
 
   fprintf (stream, _("\
--32                    create o32 ABI object file (default)\n\
--n32                   create n32 ABI object file\n\
--64                    create 64 ABI object file\n"));
+-32                    create o32 ABI object file%s\n"),
+          MIPS_DEFAULT_ABI == O32_ABI ? _(" (default)") : "");
+  fprintf (stream, _("\
+-n32                   create n32 ABI object file%s\n"),
+          MIPS_DEFAULT_ABI == N32_ABI ? _(" (default)") : "");
+  fprintf (stream, _("\
+-64                    create 64 ABI object file%s\n"),
+          MIPS_DEFAULT_ABI == N64_ABI ? _(" (default)") : "");
 }
 
 #ifdef TE_IRIX