2013-05-06 Paul Brook <paul@codesourcery.com>
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index dcea7bcf2692f5333827e357141509b24373f50b..6eff83672c63b4b6fff451d14a53762232f48401 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
@@ -171,6 +171,10 @@ struct mips_cl_insn
 
   /* True if this instruction is complete.  */
   unsigned int complete_p : 1;
+
+  /* True if this instruction is cleared from history by unconditional
+     branch.  */
+  unsigned int cleared_p : 1;
 };
 
 /* The ABI to use.  */
@@ -500,6 +504,10 @@ static int mips_32bitmode = 0;
 /* True if CPU has seq/sne and seqi/snei instructions.  */
 #define CPU_HAS_SEQ(CPU)       (CPU_IS_OCTEON (CPU))
 
+/* True, if CPU has support for ldc1 and sdc1. */
+#define CPU_HAS_LDC1_SDC1(CPU) \
+   ((mips_opts.isa != ISA_MIPS1) && ((CPU) != CPU_R5900))
+
 /* True if mflo and mfhi can be immediately followed by instructions
    which write to the HI and LO registers.
 
@@ -518,6 +526,7 @@ static int mips_32bitmode = 0;
    || mips_opts.isa == ISA_MIPS64                     \
    || mips_opts.isa == ISA_MIPS64R2                   \
    || mips_opts.arch == CPU_R4010                     \
+   || mips_opts.arch == CPU_R5900                     \
    || mips_opts.arch == CPU_R10000                    \
    || mips_opts.arch == CPU_R12000                    \
    || mips_opts.arch == CPU_R14000                    \
@@ -535,6 +544,7 @@ static int mips_32bitmode = 0;
 #define gpr_interlocks                                \
   (mips_opts.isa != ISA_MIPS1                         \
    || mips_opts.arch == CPU_R3900                     \
+   || mips_opts.arch == CPU_R5900                     \
    || mips_opts.micromips                             \
    )
 
@@ -1304,9 +1314,6 @@ static struct {
 \f
 /* Prototypes for static functions.  */
 
-#define internalError()                                                        \
-    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
-
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 static void append_insn
@@ -1465,7 +1472,9 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"section", s_change_section, 0},
   {"short", s_cons, 1},
   {"single", s_float_cons, 'f'},
+  {"stabd", s_mips_stab, 'd'},
   {"stabn", s_mips_stab, 'n'},
+  {"stabs", s_mips_stab, 's'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
 
@@ -1679,6 +1688,7 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
   insn->noreorder_p = (mips_opts.noreorder > 0);
   insn->mips16_absolute_jump_p = 0;
   insn->complete_p = 0;
+  insn->cleared_p = 0;
 }
 
 /* Record the current MIPS16/microMIPS mode in now_seg.  */
@@ -2321,8 +2331,7 @@ is_delay_slot_valid (const struct mips_opcode *mo)
     return TRUE;
 
   if (mo->pinfo == INSN_MACRO)
-    return ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0
-           ? TRUE : FALSE);
+    return (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0;
   if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
       && micromips_insn_length (mo) != 4)
     return FALSE;
@@ -2735,6 +2744,28 @@ jalr_reloc_p (bfd_reloc_code_real_type reloc)
   return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
 }
 
+/* Return true if RELOC is a PC-relative relocation that does not have
+   full address range.  */
+
+static inline bfd_boolean
+limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  switch (reloc)
+    {
+    case BFD_RELOC_16_PCREL_S2:
+    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
+    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
+      return TRUE;
+
+    case BFD_RELOC_32_PCREL:
+      return HAVE_64BIT_ADDRESSES;
+
+    default:
+      return FALSE;
+    }
+}
+
 /* Return true if the given relocation might need a matching %lo().
    This is only "might" because SVR4 R_MIPS_GOT16 relocations only
    need a matching %lo() when applied to local symbols.  */
@@ -3736,10 +3767,13 @@ fix_loongson2f (struct mips_cl_insn * ip)
 
 /* 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.  */
+   with the previous instruction.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
 
 static bfd_boolean
-can_swap_branch_p (struct mips_cl_insn *ip)
+can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr,
+  bfd_reloc_code_real_type *reloc_type)
 {
   unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
   unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
@@ -3858,13 +3892,64 @@ can_swap_branch_p (struct mips_cl_insn *ip)
       && 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
+      /* Check if instruction has a parameter, ignore "j $31". */
+      && (address_expr != NULL)
+      /* Parameter must be 16 bit. */
+      && (*reloc_type == BFD_RELOC_16_PCREL_S2)
+      /* Branch to same segment. */
+      && (S_GET_SEGMENT(address_expr->X_add_symbol) == now_seg)
+      /* Branch to same code fragment. */
+      && (symbol_get_frag(address_expr->X_add_symbol) == frag_now)
+      /* Can only calculate branch offset if value is known. */
+      && symbol_constant_p(address_expr->X_add_symbol)
+      /* Check if branch is really conditional. */
+      && !((ip->insn_opcode & 0xffff0000) == 0x10000000   /* beq $0,$0 */
+       || (ip->insn_opcode & 0xffff0000) == 0x04010000   /* bgez $0 */
+       || (ip->insn_opcode & 0xffff0000) == 0x04110000)) /* bgezal $0 */
+    {
+      int distance;
+      /* Check if loop is shorter than 6 instructions including
+         branch and delay slot.  */
+      distance = frag_now_fix() - S_GET_VALUE(address_expr->X_add_symbol);
+      if (distance <= 20)
+        {
+          int i;
+          int rv;
+
+          rv = FALSE;
+          /* When the loop includes branches or jumps,
+             it is not a short loop. */
+          for (i = 0; i < (distance / 4); i++)
+            {
+              if ((history[i].cleared_p)
+                  || delayed_branch_p(&history[i]))
+                {
+                  rv = TRUE;
+                  break;
+                }
+            }
+          if (rv == FALSE)
+            {
+              /* Insert nop after branch to fix short loop. */
+              return FALSE;
+            }
+        }
+    }
+
   return TRUE;
 }
 
-/* Decide how we should add IP to the instruction stream.  */
+/* Decide how we should add IP to the instruction stream.
+   ADDRESS_EXPR is an operand of the instruction to be used with
+   RELOC_TYPE.  */
 
 static enum append_method
-get_append_method (struct mips_cl_insn *ip)
+get_append_method (struct mips_cl_insn *ip, expressionS *address_expr,
+  bfd_reloc_code_real_type *reloc_type)
 {
   unsigned long pinfo;
 
@@ -3880,7 +3965,8 @@ get_append_method (struct mips_cl_insn *ip)
   /* Otherwise, it's our responsibility to fill branch delay slots.  */
   if (delayed_branch_p (ip))
     {
-      if (!branch_likely_p (ip) && can_swap_branch_p (ip))
+      if (!branch_likely_p (ip)
+         && can_swap_branch_p (ip, address_expr, reloc_type))
        return APPEND_SWAP;
 
       pinfo = ip->insn_mo->pinfo;
@@ -4261,7 +4347,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
        }
     }
 
-  method = get_append_method (ip);
+  method = get_append_method (ip, address_expr, reloc_type);
   branch_disp = method == APPEND_SWAP ? insn_length (history) : 0;
 
 #ifdef OBJ_ELF
@@ -4464,6 +4550,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              || lo16_reloc_p (reloc_type[0])))
        ip->fixp[0]->fx_no_overflow = 1;
 
+      /* These relocations can have an addend that won't fit in 2 octets.  */
+      if (reloc_type[0] == BFD_RELOC_MICROMIPS_7_PCREL_S1
+         || reloc_type[0] == BFD_RELOC_MICROMIPS_10_PCREL_S1)
+       ip->fixp[0]->fx_no_overflow = 1;
+
       if (mips_relax.sequence)
        {
          if (mips_relax.first_fixup == 0)
@@ -4574,7 +4665,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   /* If we have just completed an unconditional branch, clear the history.  */
   if ((delayed_branch_p (&history[1]) && uncond_branch_p (&history[1]))
       || (compact_branch_p (&history[0]) && uncond_branch_p (&history[0])))
-    mips_no_prev_insn ();
+    {
+      unsigned int i;
+
+      mips_no_prev_insn ();
+
+      for (i = 0; i < ARRAY_SIZE (history); i++)
+       history[i].cleared_p = 1;
+    }
 
   /* We need to emit a label at the end of branch-likely macros.  */
   if (emit_branch_likely_macro)
@@ -4587,7 +4685,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
   mips_clear_insn_labels ();
 }
 
-/* Forget that there was any previous instruction or label.  */
+/* Forget that there was any previous instruction or label.
+   When BRANCH is true, the branch history is also flushed.  */
 
 static void
 mips_no_prev_insn (void)
@@ -4954,7 +5053,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              continue;
 
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
@@ -5158,12 +5257,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              break;
 
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
        default:
-         internalError ();
+         abort ();
        }
       break;
     }
@@ -8854,7 +8953,7 @@ macro (struct mips_cl_insn *ip)
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
-         if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
+         if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
            {
              macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
                           BFD_RELOC_MIPS_LITERAL, mips_gp_register);
@@ -8877,7 +8976,7 @@ macro (struct mips_cl_insn *ip)
              macro_build_lui (&offset_expr, AT);
            }
 
-         if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
+         if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
            {
              macro_build (&offset_expr, "ldc1", "T,o(b)",
                           treg, BFD_RELOC_LO16, AT);
@@ -8894,7 +8993,7 @@ macro (struct mips_cl_insn *ip)
       r = BFD_RELOC_LO16;
     dob:
       gas_assert (!mips_opts.micromips);
-      gas_assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
       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
@@ -8906,7 +9005,7 @@ macro (struct mips_cl_insn *ip)
 
     case M_S_DOB:
       gas_assert (!mips_opts.micromips);
-      gas_assert (mips_opts.isa == ISA_MIPS1);
+      gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
       /* 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)",
@@ -8932,7 +9031,7 @@ macro (struct mips_cl_insn *ip)
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
-      if (mips_opts.isa != ISA_MIPS1)
+      if (CPU_HAS_LDC1_SDC1 (mips_opts.arch))
        {
          s = "ldc1";
          goto ld_st;
@@ -8945,7 +9044,7 @@ macro (struct mips_cl_insn *ip)
       /* Itbl support may require additional care here.  */
       coproc = 1;
       fmt = "T,o(b)";
-      if (mips_opts.isa != ISA_MIPS1)
+      if (CPU_HAS_LDC1_SDC1 (mips_opts.arch))
        {
          s = "sdc1";
          goto ld_st;
@@ -8953,6 +9052,16 @@ macro (struct mips_cl_insn *ip)
       s = "swc1";
       goto ldd_std;
 
+    case M_LQ_AB:
+      fmt = "t,o(b)";
+      s = "lq";
+      goto ld;
+
+    case M_SQ_AB:
+      fmt = "t,o(b)";
+      s = "sq";
+      goto ld_st;
+
     case M_LD_AB:
       fmt = "t,o(b)";
       if (HAVE_64BIT_GPRS)
@@ -9265,8 +9374,15 @@ macro (struct mips_cl_insn *ip)
     case M_DMUL:
       dbl = 1;
     case M_MUL:
+      if (mips_opts.arch == CPU_R5900)
+        {
+          macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", dreg, sreg, treg);
+        }
+      else
+        {
       macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
       macro_build (NULL, "mflo", MFHL_FMT, dreg);
+        }
       break;
 
     case M_DMUL_I:
@@ -10056,7 +10172,7 @@ mips16_macro (struct mips_cl_insn *ip)
   switch (mask)
     {
     default:
-      internalError ();
+      abort ();
 
     case M_DDIV_3:
       dbl = 1;
@@ -10634,7 +10750,7 @@ mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
     /* Let a macro pass, we'll catch it later when it is expanded.  */
     return 1;
 
-  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa))
+  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa) || (mips_opts.arch == CPU_R5900))
     {
       /* Allow odd registers for single-precision ops.  */
       switch (insn->pinfo & (FP_S | FP_D))
@@ -10698,6 +10814,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   unsigned int destregno = 0;
   unsigned int lastpos = 0;
   unsigned int limlo, limhi;
+  int sizelo;
   char *s_reset;
   offsetT min_range, max_range;
   long opend;
@@ -11204,7 +11321,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                    while (imm->type && imm->type != *args)
                      ++imm;
                    if (! imm->type)
-                     internalError ();
+                     abort ();
                    my_getExpression (&imm_expr, s);
                    check_absolute_expr (ip, &imm_expr);
                    if ((unsigned long) imm_expr.X_add_number & ~imm->mask)
@@ -11282,23 +11399,25 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                case 'C':               /* ext size, becomes MSBD.  */
                  limlo = 1;
                  limhi = 32;
+                 sizelo = 1;
                  goto do_msbd;
                case 'G':
                  limlo = 33;
                  limhi = 64;
+                 sizelo = 33;
                  goto do_msbd;
                case 'H':
                  limlo = 33;
                  limhi = 64;
+                 sizelo = 1;
                  goto do_msbd;
                do_msbd:
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
-                 /* Check for negative input so that small negative numbers
-                    will not succeed incorrectly.  The checks against
-                    (pos+size) transitively check "size" itself,
-                    assuming that "pos" is reasonable.  */
-                 if ((long) imm_expr.X_add_number < 0
+                 /* The checks against (pos+size) don't transitively check
+                    "size" itself, assuming that "pos" is reasonable.
+                    We also need to check the lower bound of "size".  */
+                 if ((long) imm_expr.X_add_number < sizelo
                      || ((unsigned long) imm_expr.X_add_number
                          + lastpos) < limlo
                      || ((unsigned long) imm_expr.X_add_number
@@ -11785,6 +11904,10 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                as_warn (_("Invalid performance register (%lu)"),
                         (unsigned long) imm_expr.X_add_number);
+             if (imm_expr.X_add_number != 0 && mips_opts.arch == CPU_R5900
+               && (!strcmp(insn->name,"mfps") || !strcmp(insn->name,"mtps")))
+               as_warn (_("Invalid performance register (%lu)"),
+                 (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (0, PERFREG, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
@@ -12409,6 +12532,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            case 'u':           /* Upper 16 bits.  */
+             *imm_reloc = BFD_RELOC_LO16;
              if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
                  && imm_expr.X_op == O_constant
                  && (imm_expr.X_add_number < 0
@@ -12734,7 +12858,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
 
                  if (regno == ILLEGAL_REG)
@@ -12807,7 +12931,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
                  continue;
 
@@ -13271,7 +13395,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
            default:
              as_bad (_("Bad char = '%c'\n"), *args);
-             internalError ();
+             abort ();
            }
          break;
        }
@@ -13548,7 +13672,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  break;
 
                default:
-                 internalError ();
+                 abort ();
                }
 
              if (regno == ILLEGAL_REG)
@@ -13581,7 +13705,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
                  break;
                default:
-                 internalError ();
+                 abort ();
                }
 
              lastregno = regno;
@@ -13940,7 +14064,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            default:
-             internalError ();
+             abort ();
            }
          break;
        }
@@ -15295,6 +15419,9 @@ md_pcrel_from (fixS *fixP)
       /* Return the address of the delay slot.  */
       return addr + 4;
 
+    case BFD_RELOC_32_PCREL:
+      return addr;
+
     default:
       /* We have no relocation type for PC relative MIPS16 instructions.  */
       if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
@@ -15517,7 +15644,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
-             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
+             || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
+             || fixP->fx_r_type == BFD_RELOC_32_PCREL);
 
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
@@ -15665,6 +15793,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
     case BFD_RELOC_RVA:
     case BFD_RELOC_32:
+    case BFD_RELOC_32_PCREL:
     case BFD_RELOC_16:
       /* If we are deleting this reloc entry, we must fill in the
         value now.  This can happen if we have a .word which is not
@@ -15751,7 +15880,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     default:
-      internalError ();
+      abort ();
     }
 
   /* Remember value for tc_gen_reloc.  */
@@ -16375,7 +16504,14 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
        case ISA_MIPS64:
        case ISA_MIPS64R2:
          mips_opts.gp32 = 0;
+         if (mips_opts.arch == CPU_R5900)
+           {
+               mips_opts.fp32 = 1;
+           }
+         else
+           {
          mips_opts.fp32 = 0;
+           }
          break;
        default:
          as_bad (_("unknown ISA level %s"), name + 4);
@@ -16517,6 +16653,9 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
   symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   macro_build_lui (&ex, mips_gp_register);
   macro_build (&ex, "addiu", "t,r,j", mips_gp_register,
@@ -16526,6 +16665,7 @@ s_cpload (int ignore ATTRIBUTE_UNUSED)
                 mips_gp_register, reg);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16602,6 +16742,9 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   SKIP_WHITESPACE ();
   expression (&ex_sym);
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16649,6 +16792,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
 
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16706,11 +16850,15 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED)
   ex.X_op_symbol = NULL;
   ex.X_add_number = mips_cprestore_offset;
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   macro_build_ldst_constoffset (&ex, ADDRESS_STORE_INSN, mips_gp_register,
                                SP, HAVE_64BIT_ADDRESSES);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16741,6 +16889,9 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16756,6 +16907,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
                 mips_cpreturn_register, 0);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16935,12 +17087,16 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   /* Add $gp to the register named as an argument.  */
   macro_start ();
   reg = tc_get_register (0);
   macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
@@ -16961,18 +17117,24 @@ s_insn (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-/* Handle a .stabn directive.  We need these in order to mark a label
-   as being a mips16 text label correctly.  Sometimes the compiler
-   will emit a label, followed by a .stabn, and then switch sections.
-   If the label and .stabn are in mips16 mode, then the label is
-   really a mips16 text label.  */
+/* Handle a .stab[snd] directive.  Ideally these directives would be
+   implemented in a transparent way, so that removing them would not
+   have any effect on the generated instructions.  However, s_stab
+   internally changes the section, so in practice we need to decide
+   now whether the preceding label marks compressed code.  We do not
+   support changing the compression mode of a label after a .stab*
+   directive, such as in:
+
+   foo:
+       .stabs ...
+       .set mips16
+
+   so the current mode wins.  */
 
 static void
 s_mips_stab (int type)
 {
-  if (type == 'n')
-    mips_mark_labels ();
-
+  mips_mark_labels ();
   s_stab (type);
 }
 
@@ -17679,11 +17841,12 @@ mips_fix_adjustable (fixS *fixp)
     return 0;
 
   /* There is no place to store an in-place offset for JALR relocations.
-     Likewise an in-range offset of PC-relative relocations may overflow
-     the in-place relocatable field if recalculated against the start
-     address of the symbol's containing section.  */
+     Likewise an in-range offset of limited PC-relative relocations may
+     overflow the in-place relocatable field if recalculated against the
+     start address of the symbol's containing section.  */
   if (HAVE_IN_PLACE_ADDENDS
-      && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type)))
+      && (limited_pcrel_reloc_p (fixp->fx_r_type)
+         || jalr_reloc_p (fixp->fx_r_type)))
     return 0;
 
 #ifdef OBJ_ELF
@@ -17763,7 +17926,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
-                 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
+                 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1
+                 || fixp->fx_r_type == BFD_RELOC_32_PCREL);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
@@ -19077,6 +19241,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "r4600",          0,                       ISA_MIPS3,      CPU_R4600 },
   { "orion",          0,                       ISA_MIPS3,      CPU_R4600 },
   { "r4650",          0,                       ISA_MIPS3,      CPU_R4650 },
+  { "r5900",          0,                       ISA_MIPS3,      CPU_R5900 },
   /* ST Microelectronics Loongson 2E and 2F cores */
   { "loongson2e",     0,                       ISA_MIPS3,   CPU_LOONGSON_2E },
   { "loongson2f",     0,                       ISA_MIPS3,   CPU_LOONGSON_2F },
This page took 0.039094 seconds and 4 git commands to generate.