2010-03-15 Thomas Schwinge <thomas@codesourcery.com>
[binutils-gdb.git] / gas / config / tc-mips.c
index 6b8b4df0ab0de98f55b171015bbe52451fa3a5df..f901ae405ea563ee7e75078715aab70022dc47bb 100644 (file)
@@ -1,6 +1,7 @@
 /* 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  Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   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
@@ -290,6 +291,18 @@ static int file_ase_mips16;
                              || mips_opts.isa == ISA_MIPS64            \
                              || mips_opts.isa == ISA_MIPS64R2)
 
+/* True if we want to create R_MIPS_JALR for jalr $25.  */
+#ifdef TE_IRIX
+#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
+#else
+/* As a GNU extension, we use R_MIPS_JALR for o32 too.  However,
+   because there's no place for any addend, the only acceptable
+   expression is a bare symbol.  */
+#define MIPS_JALR_HINT_P(EXPR) \
+  (!HAVE_IN_PLACE_ADDENDS \
+   || ((EXPR)->X_op == O_symbol && (EXPR)->X_add_number == 0))
+#endif
+
 /* True if -mips3d was passed or implied by arguments passed on the
    command line (e.g., by -march).  */
 static int file_ase_mips3d;
@@ -739,7 +752,8 @@ static const unsigned int mips16_to_32_reg_map[] =
 
 /* Classifies the kind of instructions we're interested in when
    implementing -mfix-vr4120.  */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
   FIX_VR4120_MACC,
   FIX_VR4120_DMACC,
   FIX_VR4120_MULT,
@@ -749,6 +763,15 @@ enum fix_vr4120_class {
   NUM_FIX_VR4120_CLASSES
 };
 
+/* ...likewise -mfix-loongson2f-jump.  */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop.  */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed.  */
+static bfd_boolean mips_fix_loongson2f;
+
 /* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
    there must be at least one other instruction between an instruction
    of type X and an instruction of type Y.  */
@@ -1036,8 +1059,9 @@ static struct {
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
-  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+  (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
 static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
 static void mips16_macro_build
   (expressionS *, const char *, const char *, va_list);
 static void load_register (int, expressionS *, int);
@@ -1784,7 +1808,7 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   if (reg >= 0)
     *s = e;
   else if (types & RWARN)
-    as_warn ("Unrecognized register name `%s'", *s);
+    as_warn (_("Unrecognized register name `%s'"), *s);
 
   *e = save_c;
   if (regnop)
@@ -1792,85 +1816,6 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   return reg >= 0;
 }
 
-#define INSN_ERET  0x42000018
-#define INSN_DERET 0x4200001f
-
-/*  Implement the ERET/DERET Errata for MIPS 24k.
-    If an ERET/DERET is encountered in a noreorder block,
-    warn if the ERET/DERET is followed by a branch instruction.
-    Also warn if the ERET/DERET is the last instruction in the 
-    noreorder block.
-
-    IF an ERET/DERET is in a reorder block and is followed by a
-    branch instruction, insert a nop.  */
-
-static void
-check_for_24k_errata (struct mips_cl_insn *insn, int eret_ndx)
-{
-  bfd_boolean next_insn_is_branch = FALSE;
-
-  /* eret_ndx will be -1 for the last instruction in a section
-     and the ERET/DERET will be in insn, not history.  */
-  if (insn
-      && eret_ndx == -1
-      && (insn->insn_opcode == INSN_ERET
-         || insn->insn_opcode == INSN_DERET)
-      && insn->noreorder_p)
-    {
-      as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
-      return;
-    }
-   
-  if (history[eret_ndx].insn_opcode != INSN_ERET
-      && history[eret_ndx].insn_opcode != INSN_DERET)
-    return;
-
-  if (!insn)
-    {
-      if (history[eret_ndx].noreorder_p)
-       as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
-      return;
-    }
-
-  next_insn_is_branch = ((insn->insn_opcode == INSN_ERET)
-                        || (insn->insn_opcode == INSN_DERET)
-                        || (insn->insn_mo->pinfo
-                            & (INSN_UNCOND_BRANCH_DELAY
-                               | INSN_COND_BRANCH_DELAY
-                               | INSN_COND_BRANCH_LIKELY)));
-
-  if (next_insn_is_branch && history[eret_ndx].noreorder_p)
-    {
-      as_warn (_("ERET and DERET must be followed by a NOP on the 24K."));
-      return;
-    }
-
-  /* Emit nop if the next instruction is a branch.  */ 
-  if (next_insn_is_branch)
-    {
-      long nop_where, br_where;
-      struct frag *nop_frag, *br_frag;
-      struct mips_cl_insn br_insn, nop_insn;
-
-      emit_nop ();
-
-      nop_insn = history[eret_ndx - 1]; 
-      nop_frag = history[eret_ndx - 1].frag;
-      nop_where = history[eret_ndx - 1].where;
-
-      br_insn = history[eret_ndx];
-      br_frag = history[eret_ndx].frag;
-      br_where = history[eret_ndx].where;
-
-      move_insn (&nop_insn, br_frag, br_where);
-      move_insn (&br_insn, nop_frag, nop_where);
-
-      history[eret_ndx-1] = br_insn;
-      history[eret_ndx] = nop_insn;
-    }
-}
-
 /* Return TRUE if opcode MO is valid on the currently selected ISA and
    architecture.  If EXPANSIONP is TRUE then this check is done while
    expanding a macro.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
@@ -1985,6 +1930,8 @@ md_begin (void)
              if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
                {
                  create_insn (&nop_insn, mips_opcodes + i);
+                 if (mips_fix_loongson2f_nop)
+                   nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
                  nop_insn.fixed_p = 1;
                }
            }
@@ -2156,9 +2103,6 @@ md_begin (void)
 void
 md_mips_end (void)
 {
-  if (mips_fix_24k)
-    check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
-
   if (! ECOFF_DEBUGGING)
     md_obj_end ();
 }
@@ -2295,22 +2239,22 @@ fixup_has_matching_lo_p (fixS *fixp)
 
 static int
 insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
-              enum mips_regclass class)
+              enum mips_regclass regclass)
 {
-  if (class == MIPS16_REG)
+  if (regclass == MIPS16_REG)
     {
-      assert (mips_opts.mips16);
+      gas_assert (mips_opts.mips16);
       reg = mips16_to_32_reg_map[reg];
-      class = MIPS_GR_REG;
+      regclass = MIPS_GR_REG;
     }
 
   /* Don't report on general register ZERO, since it never changes.  */
-  if (class == MIPS_GR_REG && reg == ZERO)
+  if (regclass == MIPS_GR_REG && reg == ZERO)
     return 0;
 
-  if (class == MIPS_FP_REG)
+  if (regclass == MIPS_FP_REG)
     {
-      assert (! mips_opts.mips16);
+      gas_assert (! mips_opts.mips16);
       /* If we are called with either $f0 or $f1, we must check $f0.
         This is not optimal, because it will introduce an unnecessary
         NOP between "lwc1 $f0" and "swc1 $f1".  To fix this we would
@@ -2399,7 +2343,7 @@ mips_move_labels (void)
 
   for (l = si->label_list; l != NULL; l = l->next)
     {
-      assert (S_GET_SEGMENT (l->label) == now_seg);
+      gas_assert (S_GET_SEGMENT (l->label) == now_seg);
       symbol_set_frag (l->label, frag_now);
       val = (valueT) frag_now_fix ();
       /* mips16 text labels are stored as odd.  */
@@ -2489,7 +2433,7 @@ relax_close_frag (void)
 static void
 relax_start (symbolS *symbol)
 {
-  assert (mips_relax.sequence == 0);
+  gas_assert (mips_relax.sequence == 0);
   mips_relax.sequence = 1;
   mips_relax.symbol = symbol;
 }
@@ -2500,7 +2444,7 @@ relax_start (symbolS *symbol)
 static void
 relax_switch (void)
 {
-  assert (mips_relax.sequence == 1);
+  gas_assert (mips_relax.sequence == 1);
   mips_relax.sequence = 2;
 }
 
@@ -2509,7 +2453,7 @@ relax_switch (void)
 static void
 relax_end (void)
 {
-  assert (mips_relax.sequence == 2);
+  gas_assert (mips_relax.sequence == 2);
   relax_close_frag ();
   mips_relax.sequence = 0;
 }
@@ -2536,6 +2480,9 @@ classify_vr4120_insn (const char *name)
   return NUM_FIX_VR4120_CLASSES;
 }
 
+#define INSN_ERET  0x42000018
+#define INSN_DERET 0x4200001f
+
 /* Return the number of instructions that must separate INSN1 and INSN2,
    where INSN1 is the earlier instruction.  Return the worst-case value
    for any INSN2 if INSN2 is null.  */
@@ -2573,6 +2520,24 @@ insns_between (const struct mips_cl_insn *insn1,
       && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
     return 2;
 
+  /* If we're working around 24K errata, one instruction is required
+     if an ERET or DERET is followed by a branch instruction.  */
+  if (mips_fix_24k)
+    {
+      if (insn1->insn_opcode == INSN_ERET
+         || insn1->insn_opcode == INSN_DERET)
+       {
+         if (insn2 == NULL
+             || insn2->insn_opcode == INSN_ERET
+             || insn2->insn_opcode == INSN_DERET
+             || (insn2->insn_mo->pinfo
+                 & (INSN_UNCOND_BRANCH_DELAY
+                    | INSN_COND_BRANCH_DELAY
+                    | INSN_COND_BRANCH_LIKELY)) != 0)
+           return 1;
+       }
+    }
+
   /* If working around VR4120 errata, check for combinations that need
      a single intervening instruction.  */
   if (mips_fix_vr4120)
@@ -2661,10 +2626,10 @@ insns_between (const struct mips_cl_insn *insn1,
 
 /* Return the number of nops that would be needed to work around the
    VR4130 mflo/mfhi errata if instruction INSN immediately followed
-   the MAX_VR4130_NOPS instructions described by HISTORY.  */
+   the MAX_VR4130_NOPS instructions described by HIST.  */
 
 static int
-nops_for_vr4130 (const struct mips_cl_insn *history,
+nops_for_vr4130 (const struct mips_cl_insn *hist,
                 const struct mips_cl_insn *insn)
 {
   int i, j, reg;
@@ -2679,13 +2644,13 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 
   /* Search for the first MFLO or MFHI.  */
   for (i = 0; i < MAX_VR4130_NOPS; i++)
-    if (MF_HILO_INSN (history[i].insn_mo->pinfo))
+    if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
       {
        /* Extract the destination register.  */
        if (mips_opts.mips16)
-         reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
+         reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, hist[i])];
        else
-         reg = EXTRACT_OPERAND (RD, history[i]);
+         reg = EXTRACT_OPERAND (RD, hist[i]);
 
        /* No nops are needed if INSN reads that register.  */
        if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
@@ -2693,7 +2658,7 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 
        /* ...or if any of the intervening instructions do.  */
        for (j = 0; j < i; j++)
-         if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
+         if (insn_uses_reg (&hist[j], reg, MIPS_GR_REG))
            return 0;
 
        return MAX_VR4130_NOPS - i;
@@ -2702,12 +2667,12 @@ nops_for_vr4130 (const struct mips_cl_insn *history,
 }
 
 /* Return the number of nops that would be needed if instruction INSN
-   immediately followed the MAX_NOPS instructions given by HISTORY,
-   where HISTORY[0] is the most recent instruction.  If INSN is null,
+   immediately followed the MAX_NOPS instructions given by HIST,
+   where HIST[0] is the most recent instruction.  If INSN is null,
    return the worse-case number of nops for any instruction.  */
 
 static int
-nops_for_insn (const struct mips_cl_insn *history,
+nops_for_insn (const struct mips_cl_insn *hist,
               const struct mips_cl_insn *insn)
 {
   int i, nops, tmp_nops;
@@ -2715,14 +2680,14 @@ nops_for_insn (const struct mips_cl_insn *history,
   nops = 0;
   for (i = 0; i < MAX_DELAY_NOPS; i++)
     {
-      tmp_nops = insns_between (history + i, insn) - i;
+      tmp_nops = insns_between (hist + i, insn) - i;
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
 
   if (mips_fix_vr4130)
     {
-      tmp_nops = nops_for_vr4130 (history, insn);
+      tmp_nops = nops_for_vr4130 (hist, insn);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
@@ -2731,20 +2696,20 @@ nops_for_insn (const struct mips_cl_insn *history,
 }
 
 /* The variable arguments provide NUM_INSNS extra instructions that
-   might be added to HISTORY.  Return the largest number of nops that
+   might be added to HIST.  Return the largest number of nops that
    would be needed after the extended sequence.  */
 
 static int
-nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
+nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
 {
   va_list args;
   struct mips_cl_insn buffer[MAX_NOPS];
   struct mips_cl_insn *cursor;
   int nops;
 
-  va_start (args, history);
+  va_start (args, hist);
   cursor = buffer + num_insns;
-  memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
+  memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
   while (cursor > buffer)
     *--cursor = *va_arg (args, const struct mips_cl_insn *);
 
@@ -2757,29 +2722,77 @@ nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
    worst-case delay for the branch target.  */
 
 static int
-nops_for_insn_or_target (const struct mips_cl_insn *history,
+nops_for_insn_or_target (const struct mips_cl_insn *hist,
                         const struct mips_cl_insn *insn)
 {
   int nops, tmp_nops;
 
-  nops = nops_for_insn (history, insn);
+  nops = nops_for_insn (hist, insn);
   if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
                              | INSN_COND_BRANCH_DELAY
                              | INSN_COND_BRANCH_LIKELY))
     {
-      tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
+      tmp_nops = nops_for_sequence (2, hist, insn, NOP_INSN);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
   else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
     {
-      tmp_nops = nops_for_sequence (1, history, insn);
+      tmp_nops = nops_for_sequence (1, hist, insn);
       if (tmp_nops > nops)
        nops = tmp_nops;
     }
   return nops;
 }
 
+/* Fix NOP issue: Replace nops by "or at,at,zero".  */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "nop") == 0)
+    ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+                   jr target pc &= 'hffff_ffff_cfff_ffff.  */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+  if (strcmp (ip->insn_mo->name, "j") == 0
+      || strcmp (ip->insn_mo->name, "jr") == 0
+      || strcmp (ip->insn_mo->name, "jalr") == 0)
+    {
+      int sreg;
+      expressionS ep;
+
+      if (! mips_opts.at)
+        return;
+
+      sreg = EXTRACT_OPERAND (RS, *ip);
+      if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+        return;
+
+      ep.X_op = O_constant;
+      ep.X_add_number = 0xcfff0000;
+      macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+      ep.X_add_number = 0xffff;
+      macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+      macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+    }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+  if (mips_fix_loongson2f_nop)
+    fix_loongson2f_nop (ip);
+
+  if (mips_fix_loongson2f_jump)
+    fix_loongson2f_jump (ip);
+}
+
 /* Output an instruction.  IP is the instruction information.
    ADDRESS_EXPR is an operand of the instruction to be used with
    RELOC_TYPE.  */
@@ -2789,11 +2802,13 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             bfd_reloc_code_real_type *reloc_type)
 {
   unsigned long prev_pinfo, pinfo;
-  int hndx_24k = 0;
   relax_stateT prev_insn_frag_type = 0;
   bfd_boolean relaxed_branch = FALSE;
   segment_info_type *si = seg_info (now_seg);
 
+  if (mips_fix_loongson2f)
+    fix_loongson2f (ip);
+
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
 
@@ -2850,7 +2865,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
     {
       /* Work out how many nops in prev_nop_frag are needed by IP.  */
       int nops = nops_for_insn_or_target (history, ip);
-      assert (nops <= prev_nop_frag_holds);
+      gas_assert (nops <= prev_nop_frag_holds);
 
       /* Enforce NOPS as a minimum.  */
       if (nops > prev_nop_frag_required)
@@ -2917,7 +2932,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   else if (*reloc_type > BFD_RELOC_UNUSED)
     {
       /* We need to set up a variant frag.  */
-      assert (mips_opts.mips16 && address_expr != NULL);
+      gas_assert (mips_opts.mips16 && address_expr != NULL);
       add_relaxed_insn (ip, 4, 0,
                        RELAX_MIPS16_ENCODE
                        (*reloc_type - BFD_RELOC_UNUSED,
@@ -3347,8 +3362,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                     slot, and bump the destination address.  */
                  insert_into_history (0, 1, ip);
                  emit_nop ();
-                 if (mips_fix_24k)
-                   hndx_24k++;
                }
                
              if (mips_relax.sequence)
@@ -3389,11 +3402,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             insn information.  */
          if (pinfo & INSN_UNCOND_BRANCH_DELAY)
            {
-             /* Check for eret/deret before clearing history.  */
-             if (mips_fix_24k)
-               check_for_24k_errata (
-                       (struct mips_cl_insn *) &history[hndx_24k],
-                       hndx_24k+1);
              mips_no_prev_insn ();
            }
        }
@@ -3405,8 +3413,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             the next instruction.  */
          insert_into_history (0, 1, ip);
          emit_nop ();
-         if (mips_fix_24k)
-           hndx_24k++;
        }
       else
        insert_into_history (0, 1, ip);
@@ -3414,10 +3420,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   else
     insert_into_history (0, 1, ip);
 
-  if (mips_fix_24k)
-    check_for_24k_errata ((struct mips_cl_insn *) &history[hndx_24k],
-                         hndx_24k+1);
-
   /* We just output an insn, so the next one doesn't have a label.  */
   mips_clear_insn_labels ();
 }
@@ -3504,8 +3506,6 @@ start_noreorder (void)
 static void
 end_noreorder (void)
 {
-  if (mips_fix_24k)
-    check_for_24k_errata (NULL, 0);
 
   mips_opts.noreorder--;
   if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
@@ -3629,8 +3629,8 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
   r[1] = BFD_RELOC_UNUSED;
   r[2] = BFD_RELOC_UNUSED;
   mo = (struct mips_opcode *) hash_find (op_hash, name);
-  assert (mo);
-  assert (strcmp (name, mo->name) == 0);
+  gas_assert (mo);
+  gas_assert (strcmp (name, mo->name) == 0);
 
   while (1)
     {
@@ -3642,8 +3642,8 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
        break;
 
       ++mo;
-      assert (mo->name);
-      assert (strcmp (name, mo->name) == 0);
+      gas_assert (mo->name);
+      gas_assert (strcmp (name, mo->name) == 0);
     }
 
   create_insn (&insn, mo);
@@ -3768,7 +3768,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
        case 'j':
        case 'o':
          macro_read_relocs (&args, r);
-         assert (*r == BFD_RELOC_GPREL16
+         gas_assert (*r == BFD_RELOC_GPREL16
                  || *r == BFD_RELOC_MIPS_LITERAL
                  || *r == BFD_RELOC_MIPS_HIGHER
                  || *r == BFD_RELOC_HI16_S
@@ -3784,7 +3784,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'u':
          macro_read_relocs (&args, r);
-         assert (ep != NULL
+         gas_assert (ep != NULL
                  && (ep->X_op == O_constant
                      || (ep->X_op == O_symbol
                          && (*r == BFD_RELOC_MIPS_HIGHEST
@@ -3796,7 +3796,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'p':
-         assert (ep != NULL);
+         gas_assert (ep != NULL);
 
          /*
           * This allows macro() to pass an immediate expression for
@@ -3821,7 +3821,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'a':
-         assert (ep != NULL);
+         gas_assert (ep != NULL);
          *r = BFD_RELOC_MIPS_JMP;
          continue;
 
@@ -3839,7 +3839,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
       break;
     }
   va_end (args);
-  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (&insn, ep, r);
 }
@@ -3854,14 +3854,14 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
   mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
-  assert (mo);
-  assert (strcmp (name, mo->name) == 0);
+  gas_assert (mo);
+  gas_assert (strcmp (name, mo->name) == 0);
 
   while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
     {
       ++mo;
-      assert (mo->name);
-      assert (strcmp (name, mo->name) == 0);
+      gas_assert (mo->name);
+      gas_assert (strcmp (name, mo->name) == 0);
     }
 
   create_insn (&insn, mo);
@@ -3935,7 +3935,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
        case 'p':
        case 'q':
          {
-           assert (ep != NULL);
+           gas_assert (ep != NULL);
 
            if (ep->X_op != O_constant)
              *r = (int) BFD_RELOC_UNUSED + c;
@@ -3958,7 +3958,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
       break;
     }
 
-  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
   append_insn (&insn, ep, r);
 }
@@ -3999,13 +3999,13 @@ macro_build_jalr (expressionS *ep)
 {
   char *f = NULL;
 
-  if (HAVE_NEWABI)
+  if (MIPS_JALR_HINT_P (ep))
     {
       frag_grow (8);
       f = frag_more (0);
     }
   macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
-  if (HAVE_NEWABI)
+  if (MIPS_JALR_HINT_P (ep))
     fix_new_exp (frag_now, f - frag_now->fr_literal,
                 4, ep, FALSE, BFD_RELOC_MIPS_JALR);
 }
@@ -4024,7 +4024,7 @@ macro_build_lui (expressionS *ep, int regnum)
   const char *name = "lui";
   const char *fmt = "t,u";
 
-  assert (! mips_opts.mips16);
+  gas_assert (! mips_opts.mips16);
 
   high_expr = *ep;
 
@@ -4037,10 +4037,10 @@ macro_build_lui (expressionS *ep, int regnum)
     }
   else
     {
-      assert (ep->X_op == O_symbol);
+      gas_assert (ep->X_op == O_symbol);
       /* _gp_disp is a special case, used from s_cpload.
         __gnu_local_gp is used if mips_no_shared.  */
-      assert (mips_pic == NO_PIC
+      gas_assert (mips_pic == NO_PIC
              || (! HAVE_NEWABI
                  && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
              || (! mips_in_shared
@@ -4050,8 +4050,8 @@ macro_build_lui (expressionS *ep, int regnum)
     }
 
   mo = hash_find (op_hash, name);
-  assert (strcmp (name, mo->name) == 0);
-  assert (strcmp (fmt, mo->args) == 0);
+  gas_assert (strcmp (name, mo->name) == 0);
+  gas_assert (strcmp (fmt, mo->args) == 0);
   create_insn (&insn, mo);
 
   insn.insn_opcode = insn.insn_mo->match;
@@ -4072,7 +4072,7 @@ static void
 macro_build_ldst_constoffset (expressionS *ep, const char *op,
                              int treg, int breg, int dbl)
 {
-  assert (ep->X_op == O_constant);
+  gas_assert (ep->X_op == O_constant);
 
   /* Sign-extending 32-bit constants makes their handling easier.  */
   if (!dbl)
@@ -4225,7 +4225,7 @@ load_register (int reg, expressionS *ep, int dbl)
 
   if (ep->X_op != O_big)
     {
-      assert (ep->X_op == O_constant);
+      gas_assert (ep->X_op == O_constant);
 
       /* Sign-extending 32-bit constants makes their handling easier.  */
       if (!dbl)
@@ -4279,7 +4279,7 @@ load_register (int reg, expressionS *ep, int dbl)
     }
   else
     {
-      assert (ep->X_add_number > 2);
+      gas_assert (ep->X_add_number > 2);
       if (ep->X_add_number == 3)
        generic_bignum[3] = 0;
       else if (ep->X_add_number > 4)
@@ -4826,7 +4826,7 @@ macro (struct mips_cl_insn *ip)
   bfd_reloc_code_real_type r;
   int hold_mips_optimize;
 
-  assert (! mips_opts.mips16);
+  gas_assert (! mips_opts.mips16);
 
   treg = (ip->insn_opcode >> 16) & 0x1f;
   dreg = (ip->insn_opcode >> 11) & 0x1f;
@@ -5819,8 +5819,6 @@ macro (struct mips_cl_insn *ip)
                }
              else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
                {
-                 int dreg;
-
                  /* If we are going to add in a base register, and the
                     target register and the base register are the same,
                     then we are using AT as a temporary register.  Since
@@ -5832,7 +5830,7 @@ macro (struct mips_cl_insn *ip)
                    dreg = tempreg;
                  else
                    {
-                     assert (tempreg == AT);
+                     gas_assert (tempreg == AT);
                      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                                   treg, AT, breg);
                      dreg = treg;
@@ -5960,8 +5958,6 @@ macro (struct mips_cl_insn *ip)
            }
          else
            {
-             int dreg;
-
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -5973,7 +5969,7 @@ macro (struct mips_cl_insn *ip)
                dreg = tempreg;
              else
                {
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
@@ -6016,7 +6012,7 @@ macro (struct mips_cl_insn *ip)
                {
                  /* We must add in the base register now, as in the
                     external symbol case.  */
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  load_delay_nop ();
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
@@ -6099,8 +6095,6 @@ macro (struct mips_cl_insn *ip)
            }
          else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
            {
-             int dreg;
-
              /* If we are going to add in a base register, and the
                 target register and the base register are the same,
                 then we are using AT as a temporary register.  Since
@@ -6112,7 +6106,7 @@ macro (struct mips_cl_insn *ip)
                dreg = tempreg;
              else
                {
-                 assert (tempreg == AT);
+                 gas_assert (tempreg == AT);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                  dreg = treg;
@@ -6762,7 +6756,7 @@ macro (struct mips_cl_insn *ip)
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
             in which we are not using $at).  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          if (HAVE_NEWABI)
            {
              macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
@@ -6812,7 +6806,7 @@ macro (struct mips_cl_insn *ip)
             16 bits, because we have no way to load the upper 16 bits
             (actually, we could handle them for the subset of cases
             in which we are not using $at).  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
@@ -6851,7 +6845,7 @@ macro (struct mips_cl_insn *ip)
             Otherwise, for local symbols, we want:
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT_PAGE)
               <op>     $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
-         assert (offset_expr.X_op == O_symbol);
+         gas_assert (offset_expr.X_op == O_symbol);
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
@@ -6904,7 +6898,7 @@ macro (struct mips_cl_insn *ip)
        }
       else
        {
-         assert (offset_expr.X_op == O_symbol
+         gas_assert (offset_expr.X_op == O_symbol
                  && strcmp (segment_name (S_GET_SEGMENT
                                           (offset_expr.X_add_symbol)),
                             ".lit4") == 0
@@ -6946,7 +6940,7 @@ macro (struct mips_cl_insn *ip)
                    move_register (lreg, 0);
                  else
                    {
-                     assert (offset_expr.X_op == O_constant);
+                     gas_assert (offset_expr.X_op == O_constant);
                      load_register (lreg, &offset_expr, 0);
                    }
                }
@@ -7001,7 +6995,7 @@ macro (struct mips_cl_insn *ip)
          load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
          if (HAVE_64BIT_FPRS)
            {
-             assert (HAVE_64BIT_GPRS);
+             gas_assert (HAVE_64BIT_GPRS);
              macro_build (NULL, "dmtc1", "t,S", AT, treg);
            }
          else
@@ -7011,7 +7005,7 @@ macro (struct mips_cl_insn *ip)
                macro_build (NULL, "mtc1", "t,G", 0, treg);
              else
                {
-                 assert (offset_expr.X_op == O_constant);
+                 gas_assert (offset_expr.X_op == O_constant);
                  load_register (AT, &offset_expr, 0);
                  macro_build (NULL, "mtc1", "t,G", AT, treg);
                }
@@ -7019,7 +7013,7 @@ macro (struct mips_cl_insn *ip)
          break;
        }
 
-      assert (offset_expr.X_op == O_symbol
+      gas_assert (offset_expr.X_op == O_symbol
              && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
@@ -7036,7 +7030,7 @@ macro (struct mips_cl_insn *ip)
        }
       else
        {
-         assert (strcmp (s, RDATA_SECTION_NAME) == 0);
+         gas_assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          used_at = 1;
          if (mips_pic != NO_PIC)
            macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
@@ -7063,7 +7057,7 @@ macro (struct mips_cl_insn *ip)
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg, r, breg);
       /* FIXME: A possible overflow which I don't know how to deal
@@ -7374,7 +7368,7 @@ macro (struct mips_cl_insn *ip)
     case M_SD_OB:
       s = "sw";
     sd_ob:
-      assert (HAVE_32BIT_ADDRESSES);
+      gas_assert (HAVE_32BIT_ADDRESSES);
       macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
       macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
@@ -7615,7 +7609,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_DROL_I:
       {
        unsigned int rot;
-       char *l, *r;
+       char *l;
+       char *rr;
 
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
@@ -7635,11 +7630,11 @@ macro2 (struct mips_cl_insn *ip)
            break;
          }
        l = (rot < 0x20) ? "dsll" : "dsll32";
-       r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
+       rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
        used_at = 1;
        macro_build (NULL, l, "d,w,<", AT, sreg, rot);
-       macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
+       macro_build (NULL, rr, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
       break;
@@ -7697,7 +7692,8 @@ macro2 (struct mips_cl_insn *ip)
     case M_DROR_I:
       {
        unsigned int rot;
-       char *l, *r;
+       char *l;
+       char *rr;
 
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
@@ -7715,11 +7711,11 @@ macro2 (struct mips_cl_insn *ip)
            macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            break;
          }
-       r = (rot < 0x20) ? "dsrl" : "dsrl32";
+       rr = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
        used_at = 1;
-       macro_build (NULL, r, "d,w,<", AT, sreg, rot);
+       macro_build (NULL, rr, "d,w,<", AT, sreg, rot);
        macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
       }
@@ -7750,7 +7746,7 @@ macro2 (struct mips_cl_insn *ip)
       break;
 
     case M_S_DOB:
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when storing to memory.  */
       macro_build (&offset_expr, "swc1", "T,o(b)",
@@ -8044,7 +8040,7 @@ macro2 (struct mips_cl_insn *ip)
 
     case M_TRUNCWS:
     case M_TRUNCWD:
-      assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (mips_opts.isa == ISA_MIPS1);
       used_at = 1;
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
@@ -8760,7 +8756,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       /* If we did not find a '.', then we can quit now.  */
       if (*s != '.')
        {
-         insn_error = "unrecognized opcode";
+         insn_error = _("unrecognized opcode");
          return;
        }
 
@@ -8768,7 +8764,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
       *s++ = '\0';
       if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
        {
-         insn_error = "unrecognized opcode";
+         insn_error = _("unrecognized opcode");
          return;
        }
     }
@@ -8778,7 +8774,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
     {
       bfd_boolean ok;
 
-      assert (strcmp (insn->name, str) == 0);
+      gas_assert (strcmp (insn->name, str) == 0);
 
       ok = is_opcode_valid (insn, FALSE);
       if (! ok)
@@ -9074,7 +9070,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                 we must have a left paren.  */
              /* This is dependent on the next operand specifier
                 is a base register specification.  */
-             assert (args[1] == 'b' || args[1] == '5'
+             gas_assert (args[1] == 'b' || args[1] == '5'
                      || args[1] == '-' || args[1] == '4');
              if (*s == '\0')
                return;
@@ -9629,7 +9625,7 @@ do_msbd:
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
-               as_warn ("Improper align amount (%ld), using low bits",
+               as_warn (_("Improper align amount (%ld), using low bits"),
                         (long) imm_expr.X_add_number);
              INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
@@ -9720,15 +9716,15 @@ do_msbd:
                          check_absolute_expr (ip, &imm_expr);
                          s = expr_end;
                          if (imm_expr.X_add_number > max_el)
-                           as_bad(_("Bad element selector %ld"),
-                                  (long) imm_expr.X_add_number);
+                           as_bad (_("Bad element selector %ld"),
+                                   (long) imm_expr.X_add_number);
                          imm_expr.X_add_number &= max_el;
                          ip->insn_opcode |= (imm_expr.X_add_number
                                              << (OP_SH_VSEL +
                                                  (is_qh ? 2 : 1)));
                          imm_expr.X_op = O_absent;
                          if (*s != ']')
-                           as_warn(_("Expecting ']' found '%s'"), s);
+                           as_warn (_("Expecting ']' found '%s'"), s);
                          else
                            s++;
                        }
@@ -9839,7 +9835,7 @@ do_msbd:
                    length = f64 ? 8 : 4;
                  }
 
-               assert (length == (unsigned) (f64 ? 8 : 4));
+               gas_assert (length == (unsigned) (f64 ? 8 : 4));
 
                if (*args == 'f'
                    || (*args == 'l'
@@ -9937,7 +9933,7 @@ do_msbd:
                        newname = RDATA_SECTION_NAME;
                        break;
                      case 'l':
-                       assert (g_switch_value >= 4);
+                       gas_assert (g_switch_value >= 4);
                        newname = ".lit4";
                        break;
                      }
@@ -10076,13 +10072,13 @@ do_msbd:
                   || strcmp(str + strlen(str) - 5, "any2f") == 0
                   || strcmp(str + strlen(str) - 5, "any2t") == 0)
                  && (regno & 1) != 0)
-               as_warn(_("Condition code register should be even for %s, was %d"),
-                       str, regno);
+               as_warn (_("Condition code register should be even for %s, was %d"),
+                        str, regno);
              if ((strcmp(str + strlen(str) - 5, "any4f") == 0
                   || strcmp(str + strlen(str) - 5, "any4t") == 0)
                  && (regno & 3) != 0)
-               as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
-                       str, regno);
+               as_warn (_("Condition code register should be 0 or 4 for %s, was %d"),
+                        str, regno);
              if (*args == 'N')
                INSERT_OPERAND (BCC, *ip, regno);
              else
@@ -10240,7 +10236,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
     {
       bfd_boolean ok;
 
-      assert (strcmp (insn->name, str) == 0);
+      gas_assert (strcmp (insn->name, str) == 0);
 
       ok = is_opcode_valid_16 (insn);
       if (! ok)
@@ -10666,7 +10662,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              {
                int opcode = 0;
                int framesz = 0, seen_framesz = 0;
-               int args = 0, statics = 0, sregs = 0;
+               int nargs = 0, statics = 0, sregs = 0;
 
                while (*s != '\0')
                  {
@@ -10721,7 +10717,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                          {
                            if (!seen_framesz)
                                /* args $a0-$a3 */
-                               args |= 1 << (reg1 - 4);
+                               nargs |= 1 << (reg1 - 4);
                            else
                                /* statics $a0-$a3 */
                                statics |= 1 << (reg1 - 4);
@@ -10747,9 +10743,9 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  }
 
                /* Encode args/statics combination.  */
-               if (args & statics)
+               if (nargs & statics)
                  as_bad (_("arg/static registers overlap"));
-               else if (args == 0xf)
+               else if (nargs == 0xf)
                  /* All $a0-$a3 are args.  */
                  opcode |= MIPS16_ALL_ARGS << 16;
                else if (statics == 0xf)
@@ -10760,12 +10756,12 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                    int narg = 0, nstat = 0;
 
                    /* Count arg registers.  */
-                   while (args & 0x1)
+                   while (nargs & 0x1)
                      {
-                       args >>= 1;
+                       nargs >>= 1;
                        narg++;
                      }
-                   if (args != 0)
+                   if (nargs != 0)
                      as_bad (_("invalid arg register list"));
 
                    /* Count static registers.  */
@@ -10939,7 +10935,7 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
   while (op->type != type)
     {
       ++op;
-      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+      gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
     }
 
   if (op->unsp)
@@ -11109,7 +11105,7 @@ parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
           If not, issue an error and fall back on something safe.  */
        if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
          {
-           as_bad ("relocation %s isn't supported by the current ABI",
+           as_bad (_("relocation %s isn't supported by the current ABI"),
                    percent_op[i].str);
            *reloc = BFD_RELOC_UNUSED;
          }
@@ -11165,7 +11161,7 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
       crux_depth--;
 
   if (crux_depth > 0)
-    as_bad ("unclosed '('");
+    as_bad (_("unclosed '('"));
 
   expr_end = str;
 
@@ -11285,6 +11281,10 @@ enum options
     OPTION_MNO_7000_HILO_FIX, 
     OPTION_FIX_24K,
     OPTION_NO_FIX_24K,
+    OPTION_FIX_LOONGSON2F_JUMP,
+    OPTION_NO_FIX_LOONGSON2F_JUMP,
+    OPTION_FIX_LOONGSON2F_NOP,
+    OPTION_NO_FIX_LOONGSON2F_NOP,
     OPTION_FIX_VR4120,
     OPTION_NO_FIX_VR4120,
     OPTION_FIX_VR4130,
@@ -11373,6 +11373,10 @@ 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-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},
+  {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
   {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
   {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
   {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
@@ -11640,6 +11644,22 @@ md_parse_option (int c, char *arg)
       mips_fix_24k = 0;
       break;
 
+    case OPTION_FIX_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_JUMP:
+      mips_fix_loongson2f_jump = FALSE;
+      break;
+
+    case OPTION_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = TRUE;
+      break;
+
+    case OPTION_NO_FIX_LOONGSON2F_NOP:
+      mips_fix_loongson2f_nop = FALSE;
+      break;
+
     case OPTION_FIX_VR4120:
       mips_fix_vr4120 = 1;
       break;
@@ -11854,6 +11874,8 @@ md_parse_option (int c, char *arg)
       return 0;
     }
 
+    mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
   return 1;
 }
 \f
@@ -11930,7 +11952,7 @@ mips_after_parse_args (void)
     arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
 
   if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
-    as_bad ("-march=%s is not compatible with the selected ABI",
+    as_bad (_("-march=%s is not compatible with the selected ABI"),
            arch_info->name);
 
   mips_set_architecture (arch_info);
@@ -12033,14 +12055,14 @@ mips_after_parse_args (void)
   if (mips_opts.ase_smartmips == -1)
     mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
   if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
-      as_warn ("%s ISA does not support SmartMIPS"
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support SmartMIPS")
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   if (mips_opts.ase_dsp == -1)
     mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
   if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
-      as_warn ("%s ISA does not support DSP ASE"
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support DSP ASE")
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   if (mips_opts.ase_dspr2 == -1)
     {
@@ -12048,14 +12070,14 @@ mips_after_parse_args (void)
       mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
     }
   if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
-      as_warn ("%s ISA does not support DSP R2 ASE",
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support DSP R2 ASE"),
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   if (mips_opts.ase_mt == -1)
     mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
   if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
-      as_warn ("%s ISA does not support MT ASE",
-              mips_cpu_info_from_isa (mips_opts.isa)->name);
+    as_warn (_("%s ISA does not support MT ASE"),
+            mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   file_mips_isa = mips_opts.isa;
   file_ase_mips16 = mips_opts.mips16;
@@ -12186,7 +12208,7 @@ mips_frob_file (void)
       bfd_boolean matched_lo_p;
       fixS **hi_pos, **lo_pos, **pos;
 
-      assert (reloc_needs_lo_p (l->fixp->fx_r_type));
+      gas_assert (reloc_needs_lo_p (l->fixp->fx_r_type));
 
       /* If a GOT16 relocation turns out to be against a global symbol,
         there isn't supposed to be a matching LO.  */
@@ -12282,7 +12304,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   if (! howto)
     return;
 
-  assert (fixP->fx_size == 4
+  gas_assert (fixP->fx_size == 4
          || fixP->fx_r_type == BFD_RELOC_16
          || fixP->fx_r_type == BFD_RELOC_64
          || fixP->fx_r_type == BFD_RELOC_CTOR
@@ -12293,7 +12315,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
 
-  assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
+  gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
 
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
@@ -12515,7 +12537,7 @@ mips_align (int to, int *fill, symbolS *label)
   record_alignment (now_seg, to);
   if (label != NULL)
     {
-      assert (S_GET_SEGMENT (label) == now_seg);
+      gas_assert (S_GET_SEGMENT (label) == now_seg);
       symbol_set_frag (label, frag_now);
       S_SET_VALUE (label, (valueT) frag_now_fix ());
     }
@@ -12588,9 +12610,6 @@ s_change_sec (int sec)
 
   mips_emit_delays ();
 
-  if (mips_fix_24k)
-    check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
-
   switch (sec)
     {
     case 't':
@@ -12649,9 +12668,6 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   if (!IS_ELF)
     return;
 
-  if (mips_fix_24k)
-    check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1);
-
   section_name = input_line_pointer;
   c = get_symbol_end ();
   if (c)
@@ -12941,7 +12957,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "gp=64") == 0)
     {
       if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
-       as_warn ("%s isa does not support 64-bit registers",
+       as_warn (_("%s isa does not support 64-bit registers"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.gp32 = 0;
     }
@@ -12952,7 +12968,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "fp=64") == 0)
     {
       if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
-       as_warn ("%s isa does not support 64-bit floating point registers",
+       as_warn (_("%s isa does not support 64-bit floating point registers"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.fp32 = 0;
     }
@@ -12973,7 +12989,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "smartmips") == 0)
     {
       if (!ISA_SUPPORTS_SMARTMIPS)
-       as_warn ("%s ISA does not support SmartMIPS ASE"
+       as_warn (_("%s ISA does not support SmartMIPS ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_smartmips = 1;
     }
@@ -12990,7 +13006,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "dsp") == 0)
     {
       if (!ISA_SUPPORTS_DSP_ASE)
-       as_warn ("%s ISA does not support DSP ASE"
+       as_warn (_("%s ISA does not support DSP ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_dsp = 1;
       mips_opts.ase_dspr2 = 0;
@@ -13003,7 +13019,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "dspr2") == 0)
     {
       if (!ISA_SUPPORTS_DSPR2_ASE)
-       as_warn ("%s ISA does not support DSP R2 ASE",
+       as_warn (_("%s ISA does not support DSP R2 ASE"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_dspr2 = 1;
       mips_opts.ase_dsp = 1;
@@ -13016,7 +13032,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "mt") == 0)
     {
       if (!ISA_SUPPORTS_MT_ASE)
-       as_warn ("%s ISA does not support MT ASE"
+       as_warn (_("%s ISA does not support MT ASE")
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.ase_mt = 1;
     }
@@ -13659,7 +13675,7 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
     {
       if (S_IS_DEFINED (symbolP))
        {
-         as_bad ("ignoring attempt to redefine symbol %s",
+         as_bad (_("ignoring attempt to redefine symbol %s"),
                  S_GET_NAME (symbolP));
          ignore_rest_of_line ();
          return;
@@ -13674,7 +13690,7 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
       expression (&exp);
       if (exp.X_op != O_symbol)
        {
-         as_bad ("bad .weakext directive");
+         as_bad (_("bad .weakext directive"));
          ignore_rest_of_line ();
          return;
        }
@@ -13781,7 +13797,7 @@ nopic_need_relax (symbolS *sym, int before_relaxing)
          const char *segname;
 
          segname = segment_name (S_GET_SEGMENT (sym));
-         assert (strcmp (segname, ".lit8") != 0
+         gas_assert (strcmp (segname, ".lit8") != 0
                  && strcmp (segname, ".lit4") != 0);
          change = (strcmp (segname, ".sdata") != 0
                    && strcmp (segname, ".sbss") != 0
@@ -13858,7 +13874,7 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
   while (op->type != type)
     {
       ++op;
-      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
+      gas_assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
     }
 
   if (op->unsp)
@@ -14172,6 +14188,10 @@ mips_fix_adjustable (fixS *fixp)
       && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
     return 0;
 
+  /* There is no place to store an in-place offset for JALR relocations.  */
+  if (fixp->fx_r_type == BFD_RELOC_MIPS_JALR && HAVE_IN_PLACE_ADDENDS)
+    return 0;
+
 #ifdef OBJ_ELF
   /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
      to a floating-point stub.  The same is true for non-R_MIPS16_26
@@ -14241,7 +14261,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 
   if (fixp->fx_pcrel)
     {
-      assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
+      gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
@@ -14371,14 +14391,14 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                  /* bc[0-3][tf]l? and bc1any[24][ft] instructions can
                     have the condition reversed by tweaking a single
                     bit, and their opcodes all have 0x4???????.  */
-                 assert ((insn & 0xf1000000) == 0x41000000);
+                 gas_assert ((insn & 0xf1000000) == 0x41000000);
                  insn ^= 0x00010000;
                  break;
 
                case 0:
                  /* bltz       0x04000000      bgez    0x04010000
                     bltzal     0x04100000      bgezal  0x04110000  */
-                 assert ((insn & 0xfc0e0000) == 0x04000000);
+                 gas_assert ((insn & 0xfc0e0000) == 0x04000000);
                  insn ^= 0x00010000;
                  break;
 
@@ -14396,7 +14416,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          if (RELAX_BRANCH_LINK (fragp->fr_subtype))
            {
              /* Clear the and-link bit.  */
-             assert ((insn & 0xfc1c0000) == 0x04100000);
+             gas_assert ((insn & 0xfc1c0000) == 0x04100000);
 
              /* bltzal         0x04100000      bgezal  0x04110000
                 bltzall        0x04120000      bgezall 0x04130000  */
@@ -14520,7 +14540,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
            }
        }
 
-      assert (buf == (bfd_byte *)fragp->fr_literal
+      gas_assert (buf == (bfd_byte *)fragp->fr_literal
              + fragp->fr_fix + fragp->fr_var);
 
       fragp->fr_fix += fragp->fr_var;
@@ -14861,6 +14881,8 @@ void
 mips_handle_align (fragS *fragp)
 {
   char *p;
+  int bytes, size, excess;
+  valueT opcode;
 
   if (fragp->fr_type != rs_align_code)
     return;
@@ -14868,17 +14890,28 @@ mips_handle_align (fragS *fragp)
   p = fragp->fr_literal + fragp->fr_fix;
   if (*p)
     {
-      int bytes;
+      opcode = mips16_nop_insn.insn_opcode;
+      size = 2;
+    }
+  else
+    {
+      opcode = nop_insn.insn_opcode;
+      size = 4;
+    }
 
-      bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
-      if (bytes & 1)
-       {
-         *p++ = 0;
-         fragp->fr_fix++;
-       }
-      md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2);
-      fragp->fr_var = 2;
+  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+  excess = bytes % size;
+  if (excess != 0)
+    {
+      /* If we're not inserting a whole number of instructions,
+        pad the end of the fixed part of the frag with zeros.  */
+      memset (p, 0, excess);
+      p += excess;
+      fragp->fr_fix += excess;
     }
+
+  md_number_to_chars (p, opcode, size);
+  fragp->fr_var = size;
 }
 
 static void
@@ -15018,7 +15051,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
 
   if (p != NULL)
     {
-      assert (S_GET_NAME (p));
+      gas_assert (S_GET_NAME (p));
       if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
        as_warn (_(".end symbol does not match .ent symbol."));
 
@@ -15060,7 +15093,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
       md_flush_pending_output ();
 #endif
 
-      assert (pdr_seg);
+      gas_assert (pdr_seg);
       subseg_set (pdr_seg, 0);
 
       /* Write the symbol.  */
@@ -15118,8 +15151,6 @@ s_mips_ent (int aent)
 
       cur_proc_ptr->func_sym = symbolP;
 
-      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
       ++numprocs;
 
       if (debug_type == DEBUG_STABS)
@@ -15127,6 +15158,8 @@ s_mips_ent (int aent)
                                 S_GET_NAME (symbolP));
     }
 
+  symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
   demand_empty_rest_of_line ();
 }
 
@@ -15340,6 +15373,15 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
                                                ISA_MIPS32R2,   CPU_MIPS32R2 },
   { "74kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
                                                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 1004K cores are multiprocessor versions of the 34K.  */
+  { "1004kc",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf2_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf",         MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "1004kf1_1",      MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
+                                               ISA_MIPS32R2,   CPU_MIPS32R2 },
 
   /* MIPS 64 */
   { "5kc",            0,                       ISA_MIPS64,     CPU_MIPS64 },
@@ -15462,7 +15504,7 @@ mips_parse_cpu (const char *option, const char *cpu_string)
     if (mips_matching_cpu_name_p (p->name, cpu_string))
       return p;
 
-  as_bad ("Bad value (%s) for %s", cpu_string, option);
+  as_bad (_("Bad value (%s) for %s"), cpu_string, option);
   return 0;
 }
 
@@ -15581,6 +15623,8 @@ MIPS options:\n\
 -mmt                   generate MT instructions\n\
 -mno-mt                        do not generate MT instructions\n"));
   fprintf (stream, _("\
+-mfix-loongson2f-jump  work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop   work around Loongson2F NOP errata\n\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mfix-24k              insert a nop after ERET and DERET instructions\n\