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,
 /* 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.
    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 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.  */
 };
 
 /* 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 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.
 
 /* 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.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                    \
    || 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                     \
 #define gpr_interlocks                                \
   (mips_opts.isa != ISA_MIPS1                         \
    || mips_opts.arch == CPU_R3900                     \
+   || mips_opts.arch == CPU_R5900                     \
    || mips_opts.micromips                             \
    )
 
    || mips_opts.micromips                             \
    )
 
@@ -1304,9 +1314,6 @@ static struct {
 \f
 /* Prototypes for static functions.  */
 
 \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
 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'},
   {"section", s_change_section, 0},
   {"short", s_cons, 1},
   {"single", s_float_cons, 'f'},
+  {"stabd", s_mips_stab, 'd'},
   {"stabn", s_mips_stab, 'n'},
   {"stabn", s_mips_stab, 'n'},
+  {"stabs", s_mips_stab, 's'},
   {"text", s_change_sec, 't'},
   {"word", s_cons, 2},
 
   {"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->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.  */
 }
 
 /* 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 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;
   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 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.  */
 /* 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
 
 /* 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
 
 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;
 {
   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;
 
       && 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;
 }
 
   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
 
 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;
 
 {
   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))
     {
   /* 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;
        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
   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;
 
              || 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)
       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])))
   /* 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)
 
   /* 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 ();
 }
 
   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)
 
 static void
 mips_no_prev_insn (void)
@@ -4954,7 +5053,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              continue;
 
            default:
              continue;
 
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
            }
          continue;
 
@@ -5158,12 +5257,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              break;
 
            default:
              break;
 
            default:
-             internalError ();
+             abort ();
            }
          continue;
 
        default:
            }
          continue;
 
        default:
-         internalError ();
+         abort ();
        }
       break;
     }
        }
       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)
        {
       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);
            {
              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);
            }
 
              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);
            {
              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);
       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
       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);
 
     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)",
       /* 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)";
       /* 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;
        {
          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)";
       /* 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;
        {
          s = "sdc1";
          goto ld_st;
@@ -8953,6 +9052,16 @@ macro (struct mips_cl_insn *ip)
       s = "swc1";
       goto ldd_std;
 
       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)
     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:
     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);
       macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
       macro_build (NULL, "mflo", MFHL_FMT, dreg);
+        }
       break;
 
     case M_DMUL_I:
       break;
 
     case M_DMUL_I:
@@ -10056,7 +10172,7 @@ mips16_macro (struct mips_cl_insn *ip)
   switch (mask)
     {
     default:
   switch (mask)
     {
     default:
-      internalError ();
+      abort ();
 
     case M_DDIV_3:
       dbl = 1;
 
     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;
 
     /* 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))
     {
       /* 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;
   unsigned int destregno = 0;
   unsigned int lastpos = 0;
   unsigned int limlo, limhi;
+  int sizelo;
   char *s_reset;
   offsetT min_range, max_range;
   long opend;
   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)
                    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)
                    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;
                case 'C':               /* ext size, becomes MSBD.  */
                  limlo = 1;
                  limhi = 32;
+                 sizelo = 1;
                  goto do_msbd;
                case 'G':
                  limlo = 33;
                  limhi = 64;
                  goto do_msbd;
                case 'G':
                  limlo = 33;
                  limhi = 64;
+                 sizelo = 33;
                  goto do_msbd;
                case 'H':
                  limlo = 33;
                  limhi = 64;
                  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);
                  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
                      || ((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 && 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;
              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.  */
              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
              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:
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
 
                  if (regno == ILLEGAL_REG)
                    }
 
                  if (regno == ILLEGAL_REG)
@@ -12807,7 +12931,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                        break;
 
                      default:
                        break;
 
                      default:
-                       internalError ();
+                       abort ();
                    }
                  continue;
 
                    }
                  continue;
 
@@ -13271,7 +13395,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
            default:
              as_bad (_("Bad char = '%c'\n"), *args);
 
            default:
              as_bad (_("Bad char = '%c'\n"), *args);
-             internalError ();
+             abort ();
            }
          break;
        }
            }
          break;
        }
@@ -13548,7 +13672,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  break;
 
                default:
                  break;
 
                default:
-                 internalError ();
+                 abort ();
                }
 
              if (regno == ILLEGAL_REG)
                }
 
              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:
                  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
                  break;
                default:
-                 internalError ();
+                 abort ();
                }
 
              lastregno = regno;
                }
 
              lastregno = regno;
@@ -13940,7 +14064,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              continue;
 
            default:
              continue;
 
            default:
-             internalError ();
+             abort ();
            }
          break;
        }
            }
          break;
        }
@@ -15295,6 +15419,9 @@ md_pcrel_from (fixS *fixP)
       /* Return the address of the delay slot.  */
       return addr + 4;
 
       /* 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)
     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
   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:
 
   /* 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_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
     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:
       break;
 
     default:
-      internalError ();
+      abort ();
     }
 
   /* Remember value for tc_gen_reloc.  */
     }
 
   /* 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;
        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;
          mips_opts.fp32 = 0;
+           }
          break;
        default:
          as_bad (_("unknown ISA level %s"), name + 4);
          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;
 
   /* 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,
   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_gp_register, reg);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -16602,6 +16742,9 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
   SKIP_WHITESPACE ();
   expression (&ex_sym);
 
   SKIP_WHITESPACE ();
   expression (&ex_sym);
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16649,6 +16792,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED)
 
   macro_end ();
 
 
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
   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;
 
   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 ();
 
   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 ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -16741,6 +16889,9 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
       return;
     }
 
+  mips_mark_labels ();
+  mips_assembling_insn = TRUE;
+
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
   macro_start ();
   if (mips_cpreturn_register == -1)
     {
@@ -16756,6 +16907,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED)
                 mips_cpreturn_register, 0);
   macro_end ();
 
                 mips_cpreturn_register, 0);
   macro_end ();
 
+  mips_assembling_insn = FALSE;
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -16935,12 +17087,16 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
       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 ();
 
   /* 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 ();
 }
 
   demand_empty_rest_of_line ();
 }
 
@@ -16961,18 +17117,24 @@ s_insn (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
   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)
 {
 
 static void
 s_mips_stab (int type)
 {
-  if (type == 'n')
-    mips_mark_labels ();
-
+  mips_mark_labels ();
   s_stab (type);
 }
 
   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.
     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
   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
     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
       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.  */
 
       /* 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 },
   { "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 },
   /* 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.046092 seconds and 4 git commands to generate.