bfd/
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index f19299e1c3000ea867d598325e1d6d1b929d2570..c03cca2e0465d55087198d71c4a8631be8bf1f16 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 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008 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
@@ -235,21 +235,41 @@ struct mips_set_options
   int arch;
   /* True if ".set sym32" is in effect.  */
   bfd_boolean sym32;
+  /* True if floating-point operations are not allowed.  Changed by .set
+     softfloat or .set hardfloat, by command line options -msoft-float or
+     -mhard-float.  The default is false.  */
+  bfd_boolean soft_float;
+
+  /* True if only single-precision floating-point operations are allowed.
+     Changed by .set singlefloat or .set doublefloat, command-line options
+     -msingle-float or -mdouble-float.  The default is false.  */
+  bfd_boolean single_float;
 };
 
+/* This is the struct we use to hold the current set of options.  Note
+   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
+   -1 to indicate that they have not been initialized.  */
+
 /* True if -mgp32 was passed.  */
 static int file_mips_gp32 = -1;
 
 /* True if -mfp32 was passed.  */
 static int file_mips_fp32 = -1;
 
-/* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
-   -1 to indicate that they have not been initialized.  */
+/* 1 if -msoft-float, 0 if -mhard-float.  The default is 0.  */
+static int file_mips_soft_float = 0;
+
+/* 1 if -msingle-float, 0 if -mdouble-float.  The default is 0.   */
+static int file_mips_single_float = 0;
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, -1, 0, ATREG, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
+  /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
+  /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
+  /* mips16 */ -1, /* noreorder */ 0, /* at */ ATREG,
+  /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
+  /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
+  /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -424,6 +444,14 @@ static int mips_32bitmode = 0;
 /* True if CPU has a ror instruction.  */
 #define CPU_HAS_ROR(CPU)       CPU_HAS_DROR (CPU)
 
+/* True if CPU has seq/sne and seqi/snei instructions.  */
+#define CPU_HAS_SEQ(CPU)       ((CPU) == CPU_OCTEON)
+
+/* True if CPU does not implement the all the coprocessor insns.  For these
+   CPUs only those COP insns are accepted that are explicitly marked to be
+   available on the CPU.  ISA membership for COP insns is ignored.  */
+#define NO_ISA_COP(CPU)                ((CPU) == CPU_OCTEON)
+
 /* True if mflo and mfhi can be immediately followed by instructions
    which write to the HI and LO registers.
 
@@ -481,7 +509,17 @@ static int mips_32bitmode = 0;
 
 /* Is this a mfhi or mflo instruction?  */
 #define MF_HILO_INSN(PINFO) \
-          ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+  ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
+
+/* Returns true for a (non floating-point) coprocessor instruction.  Reading
+   or writing the condition code is only possible on the coprocessors and
+   these insns are not marked with INSN_COP.  Thus for these insns use the
+   condition-code flags unless this is the floating-point coprocessor.  */
+#define COP_INSN(PINFO)                                                        \
+  (PINFO != INSN_MACRO                                                 \
+   && (((PINFO) & INSN_COP)                                            \
+       || ((PINFO) & (INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)      \
+          && ((PINFO) & (FP_S | FP_D)) == 0)))
 
 /* MIPS PIC level.  */
 
@@ -1750,6 +1788,77 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop)
   return reg >= 0;
 }
 
+/* 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.  */
+
+static bfd_boolean
+is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
+{
+  int isa = mips_opts.isa;
+  int fp_s, fp_d;
+
+  if (mips_opts.ase_mdmx)
+    isa |= INSN_MDMX;
+  if (mips_opts.ase_dsp)
+    isa |= INSN_DSP;
+  if (mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
+    isa |= INSN_DSP64;
+  if (mips_opts.ase_dspr2)
+    isa |= INSN_DSPR2;
+  if (mips_opts.ase_mt)
+    isa |= INSN_MT;
+  if (mips_opts.ase_mips3d)
+    isa |= INSN_MIPS3D;
+  if (mips_opts.ase_smartmips)
+    isa |= INSN_SMARTMIPS;
+
+  /* For user code we don't check for mips_opts.mips16 since we want
+     to allow jalx if -mips16 was specified on the command line.  */
+  if (expansionp ? mips_opts.mips16 : file_ase_mips16)
+    isa |= INSN_MIPS16;
+
+  /* Don't accept instructions based on the ISA if the CPU does not implement
+     all the coprocessor insns. */
+  if (NO_ISA_COP (mips_opts.arch)
+      && COP_INSN (mo->pinfo))
+    isa = 0;
+
+  if (!OPCODE_IS_MEMBER (mo, isa, mips_opts.arch))
+    return FALSE;
+
+  /* Check whether the instruction or macro requires single-precision or
+     double-precision floating-point support.  Note that this information is
+     stored differently in the opcode table for insns and macros.  */
+  if (mo->pinfo == INSN_MACRO)
+    {
+      fp_s = mo->pinfo2 & INSN2_M_FP_S;
+      fp_d = mo->pinfo2 & INSN2_M_FP_D;
+    }
+  else
+    {
+      fp_s = mo->pinfo & FP_S;
+      fp_d = mo->pinfo & FP_D;
+    }
+
+  if (fp_d && (mips_opts.soft_float || mips_opts.single_float))
+    return FALSE;
+
+  if (fp_s && mips_opts.soft_float)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return TRUE if the MIPS16 opcode MO is valid on the currently
+   selected ISA and architecture.  */
+
+static bfd_boolean
+is_opcode_valid_16 (const struct mips_opcode *mo)
+{
+  return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
+}
+
 /* This function is called once, at assembler startup time.  It should set up
    all the tables, etc. that the MD part of the assembler will need.  */
 
@@ -1872,8 +1981,8 @@ md_begin (void)
       /* On a native system other than VxWorks, sections must be aligned
         to 16 byte boundaries.  When configured for an embedded ELF
         target, we don't bother.  */
-      if (strcmp (TARGET_OS, "elf") != 0
-         && strcmp (TARGET_OS, "vxworks") != 0)
+      if (strncmp (TARGET_OS, "elf", 3) != 0
+         && strncmp (TARGET_OS, "vxworks", 7) != 0)
        {
          (void) bfd_set_section_alignment (stdoutput, text_section, 4);
          (void) bfd_set_section_alignment (stdoutput, data_section, 4);
@@ -1895,7 +2004,7 @@ md_begin (void)
           running program can access it.  However, we don't load it
           if we are configured for an embedded target */
        flags = SEC_READONLY | SEC_DATA;
-       if (strcmp (TARGET_OS, "elf") != 0)
+       if (strncmp (TARGET_OS, "elf", 3) != 0)
          flags |= SEC_ALLOC | SEC_LOAD;
 
        if (mips_abi != N64_ABI)
@@ -2020,6 +2129,46 @@ md_assemble (char *str)
     }
 }
 
+/* Convenience functions for abstracting away the differences between
+   MIPS16 and non-MIPS16 relocations.  */
+
+static inline bfd_boolean
+mips16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  switch (reloc)
+    {
+    case BFD_RELOC_MIPS16_JMP:
+    case BFD_RELOC_MIPS16_GPREL:
+    case BFD_RELOC_MIPS16_GOT16:
+    case BFD_RELOC_MIPS16_CALL16:
+    case BFD_RELOC_MIPS16_HI16_S:
+    case BFD_RELOC_MIPS16_HI16:
+    case BFD_RELOC_MIPS16_LO16:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
+static inline bfd_boolean
+got16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16;
+}
+
+static inline bfd_boolean
+hi16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S;
+}
+
+static inline bfd_boolean
+lo16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16;
+}
+
 /* 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.  */
@@ -2028,11 +2177,19 @@ static inline bfd_boolean
 reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
 {
   return (HAVE_IN_PLACE_ADDENDS
-         && (reloc == BFD_RELOC_HI16_S
-             || reloc == BFD_RELOC_MIPS16_HI16_S
+         && (hi16_reloc_p (reloc)
              /* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
                 all GOT16 relocations evaluate to "G".  */
-             || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
+             || (got16_reloc_p (reloc) && mips_pic != VXWORKS_PIC)));
+}
+
+/* Return the type of %lo() reloc needed by RELOC, given that
+   reloc_needs_lo_p.  */
+
+static inline bfd_reloc_code_real_type
+matching_lo_reloc (bfd_reloc_code_real_type reloc)
+{
+  return mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16 : BFD_RELOC_LO16;
 }
 
 /* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -2042,8 +2199,7 @@ static inline bfd_boolean
 fixup_has_matching_lo_p (fixS *fixp)
 {
   return (fixp->fx_next != NULL
-         && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
-            || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
+         && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
          && fixp->fx_addsy == fixp->fx_next->fx_addsy
          && fixp->fx_offset == fixp->fx_next->fx_offset);
 }
@@ -2212,7 +2368,7 @@ mips16_mark_labels (void)
 
 #if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
       if (IS_ELF)
-       S_SET_OTHER (label, STO_MIPS16);
+       S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
 #endif
       if ((S_GET_VALUE (label) & 1) == 0
        /* Don't adjust the address if the label is global or weak, or
@@ -2825,8 +2981,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              && (reloc_type[0] == BFD_RELOC_16
                  || reloc_type[0] == BFD_RELOC_32
                  || reloc_type[0] == BFD_RELOC_MIPS_JMP
-                 || reloc_type[0] == BFD_RELOC_HI16_S
-                 || reloc_type[0] == BFD_RELOC_LO16
                  || reloc_type[0] == BFD_RELOC_GPREL16
                  || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
                  || reloc_type[0] == BFD_RELOC_GPREL32
@@ -2839,8 +2993,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                  || reloc_type[0] == BFD_RELOC_MIPS_REL16
                  || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
                  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
-                 || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
-                 || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
+                 || hi16_reloc_p (reloc_type[0])
+                 || lo16_reloc_p (reloc_type[0])))
            ip->fixp[0]->fx_no_overflow = 1;
 
          if (mips_relax.sequence)
@@ -3367,16 +3521,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
         macros will never generate MDMX, MIPS-3D, or MT instructions.  */
       if (strcmp (fmt, mo->args) == 0
          && mo->pinfo != INSN_MACRO
-         && OPCODE_IS_MEMBER (mo,
-                              (mips_opts.isa
-                               | (mips_opts.mips16 ? INSN_MIPS16 : 0)
-                               | (mips_opts.ase_dsp ? INSN_DSP : 0)
-                               | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
-                                  ? INSN_DSP64 : 0)
-                               | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
-                               | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
-                              mips_opts.arch)
-         && (mips_opts.arch != CPU_R4650 || (mo->pinfo & FP_D) == 0))
+         && is_opcode_valid (mo, TRUE))
        break;
 
       ++mo;
@@ -3424,6 +3569,10 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
              INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
              continue;
 
+           case 'Q':
+             INSERT_OPERAND (SEQI, insn, va_arg (args, int));
+             continue;
+
            default:
              internalError ();
            }
@@ -6120,11 +6269,6 @@ macro (struct mips_cl_insn *ip)
       lr = 1;
       goto ld;
     case M_LDC1_AB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       s = "ldc1";
       /* Itbl support may require additional care here.  */
       coproc = 1;
@@ -6211,11 +6355,6 @@ macro (struct mips_cl_insn *ip)
       s = "cache";
       goto st;
     case M_SDC1_AB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       s = "sdc1";
       coproc = 1;
       /* Itbl support may require additional care here.  */
@@ -6239,6 +6378,15 @@ macro (struct mips_cl_insn *ip)
       tempreg = AT;
       used_at = 1;
     ld_st:
+      if (coproc
+         && NO_ISA_COP (mips_opts.arch)
+         && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
+       {
+         as_bad (_("opcode not supported on this processor: %s"),
+                 mips_cpu_info_from_arch (mips_opts.arch)->name);
+         break;
+       }
+
       /* Itbl support may require additional care here.  */
       if (mask == M_LWC1_AB
          || mask == M_SWC1_AB
@@ -6757,11 +6905,6 @@ macro (struct mips_cl_insn *ip)
        }
 
     case M_L_DOB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
@@ -6788,11 +6931,6 @@ macro (struct mips_cl_insn *ip)
        * But, the resulting address is the same after relocation so why
        * generate the extra instruction?
        */
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       /* Itbl support may require additional care here.  */
       coproc = 1;
       if (mips_opts.isa != ISA_MIPS1)
@@ -6806,12 +6944,6 @@ macro (struct mips_cl_insn *ip)
       goto ldd_std;
 
     case M_S_DAB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
-
       if (mips_opts.isa != ISA_MIPS1)
        {
          s = "sdc1";
@@ -7123,6 +7255,14 @@ macro (struct mips_cl_insn *ip)
     case M_COP3:
       s = "c3";
     copz:
+      if (NO_ISA_COP (mips_opts.arch)
+         && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
+       {
+         as_bad (_("opcode not supported on this processor: %s"),
+                 mips_cpu_info_from_arch (mips_opts.arch)->name);
+         break;
+       }
+
       /* For now we just do C (same as Cz).  The parameter will be
          stored in insn_opcode by mips_ip.  */
       macro_build (NULL, s, "C", ip->insn_opcode);
@@ -7456,11 +7596,6 @@ macro2 (struct mips_cl_insn *ip)
       break;
 
     case M_S_DOB:
-      if (mips_opts.arch == CPU_R4650)
-       {
-         as_bad (_("opcode not supported on this processor"));
-         break;
-       }
       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.  */
@@ -7496,6 +7631,14 @@ macro2 (struct mips_cl_insn *ip)
          move_register (dreg, 0);
          break;
        }
+      if (CPU_HAS_SEQ (mips_opts.arch)
+         && -512 <= imm_expr.X_add_number
+         && imm_expr.X_add_number < 512)
+       {
+         macro_build (NULL, "seqi", "t,r,+Q", dreg, sreg,
+                      imm_expr.X_add_number);
+         break;
+       }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
@@ -7510,6 +7653,13 @@ macro2 (struct mips_cl_insn *ip)
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
        }
+      else if (CPU_HAS_SEQ (mips_opts.arch))
+       {
+         used_at = 1;
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "seq", "d,v,t", dreg, sreg, AT);
+         break;
+       }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
@@ -7643,6 +7793,14 @@ macro2 (struct mips_cl_insn *ip)
                       dreg, 0, BFD_RELOC_LO16);
          break;
        }
+      if (CPU_HAS_SEQ (mips_opts.arch)
+         && -512 <= imm_expr.X_add_number
+         && imm_expr.X_add_number < 512)
+       {
+         macro_build (NULL, "snei", "t,r,+Q", dreg, sreg,
+                      imm_expr.X_add_number);
+         break;
+       }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= 0
          && imm_expr.X_add_number < 0x10000)
@@ -7657,6 +7815,13 @@ macro2 (struct mips_cl_insn *ip)
          macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
        }
+      else if (CPU_HAS_SEQ (mips_opts.arch))
+       {
+         used_at = 1;
+         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
+         macro_build (NULL, "sne", "d,v,t", dreg, sreg, AT);
+         break;
+       }
       else
        {
          load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
@@ -8223,6 +8388,14 @@ validate_mips_insn (const struct mips_opcode *opc)
          case 't': USE_BITS (OP_MASK_RT,       OP_SH_RT);      break;
          case 'T': USE_BITS (OP_MASK_RT,       OP_SH_RT);
                    USE_BITS (OP_MASK_SEL,      OP_SH_SEL);     break;
+         case 'x': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
+         case 'X': USE_BITS (OP_MASK_BBITIND,  OP_SH_BBITIND); break;
+         case 'p': USE_BITS (OP_MASK_CINSPOS,  OP_SH_CINSPOS); break;
+         case 'P': USE_BITS (OP_MASK_CINSPOS,  OP_SH_CINSPOS); break;
+         case 'Q': USE_BITS (OP_MASK_SEQI,     OP_SH_SEQI);    break;
+         case 's': USE_BITS (OP_MASK_CINSLM1,  OP_SH_CINSLM1); break;
+         case 'S': USE_BITS (OP_MASK_CINSLM1,  OP_SH_CINSLM1); break;
+
          default:
            as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    c, opc->name, opc->args);
@@ -8452,31 +8625,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
       assert (strcmp (insn->name, str) == 0);
 
-      if (OPCODE_IS_MEMBER (insn,
-                           (mips_opts.isa
-                            /* We don't check for mips_opts.mips16 here since
-                               we want to allow jalx if -mips16 was specified
-                               on the command line.  */
-                            | (file_ase_mips16 ? INSN_MIPS16 : 0)
-                            | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
-                            | (mips_opts.ase_dsp ? INSN_DSP : 0)
-                            | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
-                               ? INSN_DSP64 : 0)
-                            | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
-                            | (mips_opts.ase_mt ? INSN_MT : 0)
-                            | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)
-                            | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
-                           mips_opts.arch))
-       ok = TRUE;
-      else
-       ok = FALSE;
-
-      if (insn->pinfo != INSN_MACRO)
-       {
-         if (mips_opts.arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
-           ok = FALSE;
-       }
-
+      ok = is_opcode_valid (insn, FALSE);
       if (! ok)
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
@@ -8946,6 +9095,116 @@ do_msbd:
                    as_bad (_("Invalid coprocessor 0 register number"));
                  break;
 
+               case 'x':
+                 /* bbit[01] and bbit[01]32 bit index.  Give error if index
+                    is not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper bit index (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'X':
+                 /* bbit[01] bit index when bbit is used but we generate
+                    bbit[01]32 because the index is over 32.  Move to the
+                    next candidate if index is not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number < 32
+                     || (unsigned) imm_expr.X_add_number > 63)
+                   break;
+                 INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number - 32);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'p':
+                 /* cins, cins32, exts and exts32 position field.  Give error
+                    if it's not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper position (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 /* Make the pos explicit to simplify +S.  */
+                 lastpos = imm_expr.X_add_number + 32;
+                 INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'P':
+                 /* cins, cins32, exts and exts32 position field.  Move to
+                    the next candidate if it's not in the valid range.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned) imm_expr.X_add_number < 32
+                     || (unsigned) imm_expr.X_add_number > 63)
+                   break;
+                 lastpos = imm_expr.X_add_number;
+                 INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number - 32);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 's':
+                 /* cins and exts length-minus-one field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((unsigned long) imm_expr.X_add_number > 31)
+                   {
+                     as_bad (_("Improper size (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'S':
+                 /* cins32/exts32 and cins/exts aliasing cint32/exts32
+                    length-minus-one field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((long) imm_expr.X_add_number < 0
+                     || (unsigned long) imm_expr.X_add_number + lastpos > 63)
+                   {
+                     as_bad (_("Improper size (%lu)"),
+                             (unsigned long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
+               case 'Q':
+                 /* seqi/snei immediate field.  */
+                 my_getExpression (&imm_expr, s);
+                 check_absolute_expr (ip, &imm_expr);
+                 if ((long) imm_expr.X_add_number < -512
+                     || (long) imm_expr.X_add_number >= 512)
+                   {
+                     as_bad (_("Improper immediate (%ld)"),
+                              (long) imm_expr.X_add_number);
+                     imm_expr.X_add_number = 0;
+                   }
+                 INSERT_OPERAND (SEQI, *ip, imm_expr.X_add_number);
+                 imm_expr.X_op = O_absent;
+                 s = expr_end;
+                 continue;
+
                default:
                  as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    *args, insn->name, insn->args);
@@ -9133,6 +9392,19 @@ do_msbd:
                  if (c == 'z' && regno != 0)
                    break;
 
+                 if (c == 's' && !strcmp (ip->insn_mo->name, "jalr"))
+                   {
+                     if (regno == lastregno)
+                       {
+                         insn_error = _("source and destinationations must be different");
+                         continue;
+                       }
+                     if (regno == 31 && lastregno == 0)
+                       {
+                         insn_error = _("a destination register must be supplied");
+                         continue;
+                       }
+                   }
        /* Now that we have assembled one operand, we use the args string
         * to figure out where it goes in the instruction.  */
                  switch (c)
@@ -9518,7 +9790,7 @@ do_msbd:
                                              | SEC_READONLY
                                              | SEC_DATA));
                    frag_align (*args == 'l' ? 2 : 3, 0, 0);
-                   if (IS_ELF && strcmp (TARGET_OS, "elf") != 0)
+                   if (IS_ELF && strncmp (TARGET_OS, "elf", 3) != 0)
                      record_alignment (new_seg, 4);
                    else
                      record_alignment (new_seg, *args == 'l' ? 2 : 3);
@@ -9731,7 +10003,7 @@ do_msbd:
          continue;
        }
       if (save_c)
-       *(--s) = save_c;
+       *(--argsStart) = save_c;
       insn_error = _("illegal operands");
       return;
     }
@@ -9811,11 +10083,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
 
       assert (strcmp (insn->name, str) == 0);
 
-      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
-       ok = TRUE;
-      else
-       ok = FALSE;
-
+      ok = is_opcode_valid_16 (insn);
       if (! ok)
        {
          if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
@@ -9869,6 +10137,8 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  /* Stuff the immediate value in now, if we can.  */
                  if (imm_expr.X_op == O_constant
                      && *imm_reloc > BFD_RELOC_UNUSED
+                     && *imm_reloc != BFD_RELOC_MIPS16_GOT16
+                     && *imm_reloc != BFD_RELOC_MIPS16_CALL16
                      && insn->pinfo != INSN_MACRO)
                    {
                      valueT tmp;
@@ -10638,6 +10908,8 @@ static const struct percent_op_match mips16_percent_op[] =
 {
   {"%lo", BFD_RELOC_MIPS16_LO16},
   {"%gprel", BFD_RELOC_MIPS16_GPREL},
+  {"%got", BFD_RELOC_MIPS16_GOT16},
+  {"%call16", BFD_RELOC_MIPS16_CALL16},
   {"%hi", BFD_RELOC_MIPS16_HI16_S}
 };
 
@@ -10944,10 +11216,18 @@ struct option md_longopts[] =
 #define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15)
   {"msym32", no_argument, NULL, OPTION_MSYM32},
   {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
-
+#define OPTION_SOFT_FLOAT (OPTION_MISC_BASE + 16)
+#define OPTION_HARD_FLOAT (OPTION_MISC_BASE + 17)
+  {"msoft-float", no_argument, NULL, OPTION_SOFT_FLOAT},
+  {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT},
+#define OPTION_SINGLE_FLOAT (OPTION_MISC_BASE + 18)
+#define OPTION_DOUBLE_FLOAT (OPTION_MISC_BASE + 19)
+  {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT},
+  {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT},
+  
   /* ELF-specific options.  */
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 16)
+#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 20)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
@@ -11307,6 +11587,22 @@ md_parse_option (int c, char *arg)
       file_mips_fp32 = 0;
       break;
 
+    case OPTION_SINGLE_FLOAT:
+      file_mips_single_float = 1;
+      break;
+
+    case OPTION_DOUBLE_FLOAT:
+      file_mips_single_float = 0;
+      break;
+
+    case OPTION_SOFT_FLOAT:
+      file_mips_soft_float = 1;
+      break;
+
+    case OPTION_HARD_FLOAT:
+      file_mips_soft_float = 0;
+      break;
+
 #ifdef OBJ_ELF
     case OPTION_MABI:
       if (!IS_ELF)
@@ -11584,6 +11880,8 @@ mips_after_parse_args (void)
   file_ase_mt = mips_opts.ase_mt;
   mips_opts.gp32 = file_mips_gp32;
   mips_opts.fp32 = file_mips_fp32;
+  mips_opts.soft_float = file_mips_soft_float;
+  mips_opts.single_float = file_mips_single_float;
 
   if (mips_flag_mdebug < 0)
     {
@@ -11693,6 +11991,7 @@ void
 mips_frob_file (void)
 {
   struct mips_hi_fixup *l;
+  bfd_reloc_code_real_type looking_for_rtype = BFD_RELOC_UNUSED;
 
   for (l = mips_hi_fixup_list; l != NULL; l = l->next)
     {
@@ -11704,7 +12003,7 @@ mips_frob_file (void)
 
       /* If a GOT16 relocation turns out to be against a global symbol,
         there isn't supposed to be a matching LO.  */
-      if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
+      if (got16_reloc_p (l->fixp->fx_r_type)
          && !pic_need_relax (l->fixp->fx_addsy, l->seg))
        continue;
 
@@ -11722,13 +12021,14 @@ mips_frob_file (void)
       hi_pos = NULL;
       lo_pos = NULL;
       matched_lo_p = FALSE;
+      looking_for_rtype = matching_lo_reloc (l->fixp->fx_r_type);
+
       for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
        {
          if (*pos == l->fixp)
            hi_pos = pos;
 
-         if (((*pos)->fx_r_type == BFD_RELOC_LO16
-              || (*pos)->fx_r_type == BFD_RELOC_MIPS16_LO16)
+         if ((*pos)->fx_r_type == looking_for_rtype
              && (*pos)->fx_addsy == l->fixp->fx_addsy
              && (*pos)->fx_offset >= l->fixp->fx_offset
              && (lo_pos == NULL
@@ -11774,8 +12074,8 @@ mips_force_relocation (fixS *fixp)
   if (HAVE_NEWABI
       && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
       && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
-         || fixp->fx_r_type == BFD_RELOC_HI16_S
-         || fixp->fx_r_type == BFD_RELOC_LO16))
+         || hi16_reloc_p (fixp->fx_r_type)
+         || lo16_reloc_p (fixp->fx_r_type)))
     return 1;
 
   return 0;
@@ -11863,6 +12163,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
     case BFD_RELOC_MIPS16_GPREL:
+    case BFD_RELOC_MIPS16_GOT16:
+    case BFD_RELOC_MIPS16_CALL16:
     case BFD_RELOC_MIPS16_HI16:
     case BFD_RELOC_MIPS16_HI16_S:
     case BFD_RELOC_MIPS16_JMP:
@@ -12119,7 +12421,7 @@ s_change_sec (int sec)
          bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
                                                  | SEC_READONLY | SEC_RELOC
                                                  | SEC_DATA));
-         if (strcmp (TARGET_OS, "elf") != 0)
+         if (strncmp (TARGET_OS, "elf", 3) != 0)
            record_alignment (seg, 4);
        }
       demand_empty_rest_of_line ();
@@ -12131,7 +12433,7 @@ s_change_sec (int sec)
        {
          bfd_set_section_flags (stdoutput, seg,
                                 SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
-         if (strcmp (TARGET_OS, "elf") != 0)
+         if (strncmp (TARGET_OS, "elf", 3) != 0)
            record_alignment (seg, 4);
        }
       demand_empty_rest_of_line ();
@@ -12460,6 +12762,14 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
       mips_opts.fp32 = 0;
     }
+  else if (strcmp (name, "softfloat") == 0)
+    mips_opts.soft_float = 1;
+  else if (strcmp (name, "hardfloat") == 0)
+    mips_opts.soft_float = 0;
+  else if (strcmp (name, "singlefloat") == 0)
+    mips_opts.single_float = 1;
+  else if (strcmp (name, "doublefloat") == 0)
+    mips_opts.single_float = 0;
   else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
     mips_opts.mips16 = 1;
@@ -13212,7 +13522,7 @@ md_section_align (asection *seg, valueT addr)
         However, Irix 5 may prefer that we align them at least to a 16
         byte boundary.  We don't bother to align the sections if we
         are targeted for an embedded system.  */
-      if (strcmp (TARGET_OS, "elf") == 0)
+      if (strncmp (TARGET_OS, "elf", 3) == 0)
         return addr;
       if (align > 4)
         align = 4;
@@ -13662,8 +13972,7 @@ mips_fix_adjustable (fixS *fixp)
      placed anywhere.  Rather than break backwards compatibility by changing
      this, it seems better not to force the issue, and instead keep the
      original symbol.  This will work with either linker behavior.  */
-  if ((fixp->fx_r_type == BFD_RELOC_LO16
-       || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
+  if ((lo16_reloc_p (fixp->fx_r_type)
        || reloc_needs_lo_p (fixp->fx_r_type))
       && HAVE_IN_PLACE_ADDENDS
       && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
@@ -13712,7 +14021,7 @@ mips_fix_adjustable (fixS *fixp)
      that we have for MIPS16 symbols.  */
   if (IS_ELF
       && fixp->fx_subsy == NULL
-      && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+      && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
          || *symbol_get_tc (fixp->fx_addsy)))
     return 0;
 #endif
@@ -14189,7 +14498,7 @@ mips_frob_file_after_relocs (void)
   count = bfd_get_symcount (stdoutput);
   for (i = 0; i < count; i++, syms++)
     {
-      if (elf_symbol (*syms)->internal_elf_sym.st_other == STO_MIPS16
+      if (ELF_ST_IS_MIPS16 (elf_symbol (*syms)->internal_elf_sym.st_other)
          && ((*syms)->value & 1) != 0)
        {
          (*syms)->value &= ~1;
@@ -14758,6 +15067,9 @@ 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 },
+  /* ST Microelectronics Loongson 2E and 2F cores */
+  { "loongson2e",     0,                       ISA_MIPS3,   CPU_LOONGSON_2E },
+  { "loongson2f",     0,                       ISA_MIPS3,   CPU_LOONGSON_2F },
 
   /* MIPS IV */
   { "r8000",          0,                       ISA_MIPS4,      CPU_R8000 },
@@ -14848,9 +15160,8 @@ static const struct mips_cpu_info mips_cpu_info_table[] =
   { "sb1a",           MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
                                                ISA_MIPS64,     CPU_SB1 },
 
-  /* ST Microelectronics Loongson 2E and 2F cores */
-  { "loongson2e",     0,      ISA_MIPS3,      CPU_LOONGSON_2E },
-  { "loongson2f",     0,      ISA_MIPS3,      CPU_LOONGSON_2F },
+  /* Cavium Networks Octeon CPU core */
+  { "octeon",        0,      ISA_MIPS64R2,   CPU_OCTEON },
 
   /* End marker */
   { NULL, 0, 0, 0 }
@@ -15078,9 +15389,15 @@ MIPS options:\n\
 -msym32                        assume all symbols have 32-bit values\n\
 -O0                    remove unneeded NOPs, do not swap branches\n\
 -O                     remove unneeded NOPs and swap branches\n\
---[no-]construct-floats [dis]allow floating point values to be constructed\n\
 --trap, --no-break     trap exception on div by 0 and mult overflow\n\
 --break, --no-trap     break exception on div by 0 and mult overflow\n"));
+  fprintf (stream, _("\
+-mhard-float           allow floating-point instructions\n\
+-msoft-float           do not allow floating-point instructions\n\
+-msingle-float         only allow 32-bit floating-point operations\n\
+-mdouble-float         allow 32-bit and 64-bit floating-point operations\n\
+--[no-]construct-floats [dis]allow floating point values to be constructed\n"
+                    ));
 #ifdef OBJ_ELF
   fprintf (stream, _("\
 -KPIC, -call_shared    generate SVR4 position independent code\n\
@@ -15110,7 +15427,7 @@ MIPS options:\n\
 }
 
 enum dwarf2_format
-mips_dwarf2_format (void)
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
 {
   if (HAVE_64BIT_SYMBOLS)
     {
This page took 0.038278 seconds and 4 git commands to generate.