svn commit: r207028 - user/jmallett/octeon/contrib/binutils/gas/config

Juli Mallett jmallett at FreeBSD.org
Wed Apr 21 23:47:04 UTC 2010


Author: jmallett
Date: Wed Apr 21 23:47:04 2010
New Revision: 207028
URL: http://svn.freebsd.org/changeset/base/207028

Log:
  Merge from Octeon cnusers SDK 1.7.2.
  
  XXX Some of these changes may be due to structural changes in binutils between
  our version and the version that the SDK is based on; I have not yet done any
  correctness checking, though I did take some small effort to minimize deltas.

Modified:
  user/jmallett/octeon/contrib/binutils/gas/config/tc-mips.c
  user/jmallett/octeon/contrib/binutils/gas/config/tc-mips.h

Modified: user/jmallett/octeon/contrib/binutils/gas/config/tc-mips.c
==============================================================================
--- user/jmallett/octeon/contrib/binutils/gas/config/tc-mips.c	Wed Apr 21 23:03:26 2010	(r207027)
+++ user/jmallett/octeon/contrib/binutils/gas/config/tc-mips.c	Wed Apr 21 23:47:04 2010	(r207028)
@@ -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 Free Software Foundation, Inc.
+   2003, 2004, 2005 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
@@ -20,8 +20,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include "as.h"
 #include "config.h"
@@ -33,6 +33,7 @@
 #include "opcode/mips.h"
 #include "itbl-ops.h"
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 
 #ifdef DEBUG
 #define DBG(x) printf x
@@ -83,6 +84,25 @@ int mips_flag_pdr = FALSE;
 int mips_flag_pdr = TRUE;
 #endif
 
+/* Control generation of error message for unsupported instructions in
+   Octeon. Octeon does not have floating point, and all the instructions
+   that use floating point registers are not allowed in Elf targets but 
+   are allowed in Linux targets by default.  */
+#ifdef OCTEON_ERROR_ON_UNSUPPORTED
+static int octeon_error_on_unsupported = 1;
+#else
+static int octeon_error_on_unsupported = 0;
+#endif
+
+/* Control generation of Octeon/MIPS unaligned load/store instructions.
+   For ELF target, default to Octeon load/store instructions.
+   For Linux target, default to MIPS load/store instructions.  */
+#ifdef OCTEON_USE_UNALIGN
+static int octeon_use_unalign = 1;
+#else
+static int octeon_use_unalign = 0;
+#endif
+
 #include "ecoff.h"
 
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
@@ -111,9 +131,7 @@ static char *mips_regmask_frag;
 extern int target_big_endian;
 
 /* The name of the readonly data section.  */
-#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
-			    ? ".data" \
-			    : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
+#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
 			    ? ".rdata" \
 			    : OUTPUT_FLAVOR == bfd_target_coff_flavour \
 			    ? ".rdata" \
@@ -121,6 +139,43 @@ extern int target_big_endian;
 			    ? ".rodata" \
 			    : (abort (), ""))
 
+/* Information about an instruction, including its format, operands
+   and fixups.  */
+struct mips_cl_insn
+{
+  /* The opcode's entry in mips_opcodes or mips16_opcodes.  */
+  const struct mips_opcode *insn_mo;
+
+  /* True if this is a mips16 instruction and if we want the extended
+     form of INSN_MO.  */
+  bfd_boolean use_extend;
+
+  /* The 16-bit extension instruction to use when USE_EXTEND is true.  */
+  unsigned short extend;
+
+  /* The 16-bit or 32-bit bitstring of the instruction itself.  This is
+     a copy of INSN_MO->match with the operands filled in.  */
+  unsigned long insn_opcode;
+
+  /* The frag that contains the instruction.  */
+  struct frag *frag;
+
+  /* The offset into FRAG of the first instruction byte.  */
+  long where;
+
+  /* The relocs associated with the instruction, if any.  */
+  fixS *fixp[3];
+
+  /* True if this entry cannot be moved from its current position.  */
+  unsigned int fixed_p : 1;
+
+  /* True if this instruction occured in a .set noreorder block.  */
+  unsigned int noreorder_p : 1;
+
+  /* True for mips16 instructions that jump to an absolute address.  */
+  unsigned int mips16_absolute_jump_p : 1;
+};
+
 /* The ABI to use.  */
 enum mips_abi_level
 {
@@ -138,6 +193,10 @@ static enum mips_abi_level mips_abi = NO
 /* Whether or not we have code that can call pic code.  */
 int mips_abicalls = FALSE;
 
+/* Whether or not we have code which can be put into a shared
+   library.  */
+static bfd_boolean mips_in_shared = TRUE;
+
 /* This is the set of options which may be modified by the .set
    pseudo-op.  We use a struct so that .set push and .set pop are more
    reliable.  */
@@ -153,6 +212,8 @@ struct mips_set_options
      command line options, and based on the default architecture.  */
   int ase_mips3d;
   int ase_mdmx;
+  int ase_dsp;
+  int ase_mt;
   /* Whether we are assembling for the mips16 processor.  0 if we are
      not, 1 if we are, and -1 if the value has not been initialized.
      Changed by `.set mips16' and `.set nomips16', and the -mips16 and
@@ -187,6 +248,8 @@ struct mips_set_options
   /* MIPS architecture (CPU) type.  Changed by .set arch=FOO, the -march
      command line option, and the default CPU.  */
   int arch;
+  /* True if ".set sym32" is in effect.  */
+  bfd_boolean sym32;
 };
 
 /* True if -mgp32 was passed.  */
@@ -201,7 +264,7 @@ static int file_mips_fp32 = -1;
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN
+  ISA_UNKNOWN, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -225,6 +288,14 @@ static int file_ase_mips3d;
    command line (e.g., by -march).  */
 static int file_ase_mdmx;
 
+/* True if -mdsp was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_dsp;
+
+/* True if -mmt was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_mt;
+
 /* The argument of the -march= flag.  The architecture we are assembling.  */
 static int file_mips_arch = CPU_UNKNOWN;
 static const char *mips_arch_string;
@@ -268,6 +339,12 @@ static int mips_32bitmode = 0;
    || (ISA) == ISA_MIPS64R2	\
    )
 
+/* Return true if ISA supports ins instructions. */
+#define ISA_HAS_INS(ISA) ( \
+  (ISA) == ISA_MIPS32R2    \
+  || (ISA) == ISA_MIPS64R2 \
+  )
+
 #define HAVE_32BIT_GPRS		                   \
     (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
 
@@ -284,15 +361,16 @@ static int mips_32bitmode = 0;
 /* True if relocations are stored in-place.  */
 #define HAVE_IN_PLACE_ADDENDS (!HAVE_NEWABI)
 
-/* We can only have 64bit addresses if the object file format
-   supports it.  */
-#define HAVE_32BIT_ADDRESSES                           \
-   (HAVE_32BIT_GPRS                                    \
-    || ((bfd_arch_bits_per_address (stdoutput) == 32   \
-         || ! HAVE_64BIT_OBJECTS)                      \
-        && mips_pic != EMBEDDED_PIC))
-
-#define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES)
+/* The ABI-derived address size.  */
+#define HAVE_64BIT_ADDRESSES \
+  (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
+#define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES)
+
+/* The size of symbolic constants (i.e., expressions of the form
+   "SYMBOL" or "SYMBOL + OFFSET").  */
+#define HAVE_32BIT_SYMBOLS \
+  (HAVE_32BIT_ADDRESSES || !HAVE_64BIT_OBJECTS || mips_opts.sym32)
+#define HAVE_64BIT_SYMBOLS (!HAVE_32BIT_SYMBOLS)
 
 /* Addresses are loaded in different ways, depending on the address size
    in use.  The n32 ABI Documentation also mandates the use of additions
@@ -322,6 +400,14 @@ static int mips_32bitmode = 0;
 #define CPU_HAS_MDMX(cpu)	(FALSE                 \
 				 )
 
+/* Return true if the given CPU supports the DSP ASE.  */
+#define CPU_HAS_DSP(cpu)	(FALSE                 \
+				 )
+
+/* Return true if the given CPU supports the MT ASE.  */
+#define CPU_HAS_MT(cpu)		(FALSE                 \
+				 )
+
 /* True if CPU has a dror instruction.  */
 #define CPU_HAS_DROR(CPU)	((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
 
@@ -349,7 +435,6 @@ static int mips_32bitmode = 0;
    || mips_opts.arch == CPU_R10000                    \
    || mips_opts.arch == CPU_R12000                    \
    || mips_opts.arch == CPU_RM7000                    \
-   || mips_opts.arch == CPU_SB1                       \
    || mips_opts.arch == CPU_VR5500                    \
    )
 
@@ -360,8 +445,6 @@ static int mips_32bitmode = 0;
    level I.  */
 #define gpr_interlocks \
   (mips_opts.isa != ISA_MIPS1  \
-   || mips_opts.arch == CPU_VR5400  \
-   || mips_opts.arch == CPU_VR5500  \
    || mips_opts.arch == CPU_R3900)
 
 /* Whether the processor uses hardware interlocks to avoid delays
@@ -377,9 +460,6 @@ static int mips_32bitmode = 0;
     && mips_opts.isa != ISA_MIPS2                     \
     && mips_opts.isa != ISA_MIPS3)                    \
    || mips_opts.arch == CPU_R4300                     \
-   || mips_opts.arch == CPU_VR5400                    \
-   || mips_opts.arch == CPU_VR5500                    \
-   || mips_opts.arch == CPU_SB1                       \
    )
 
 /* Whether the processor uses hardware interlocks to protect reads
@@ -521,44 +601,27 @@ static int mips_optimize = 2;
    equivalent to seeing no -g option at all.  */
 static int mips_debug = 0;
 
-/* The previous instruction.  */
-static struct mips_cl_insn prev_insn;
-
-/* The instruction before prev_insn.  */
-static struct mips_cl_insn prev_prev_insn;
+/* The maximum number of NOPs needed to avoid the VR4130 mflo/mfhi errata.  */
+#define MAX_VR4130_NOPS 4
 
-/* If we don't want information for prev_insn or prev_prev_insn, we
-   point the insn_mo field at this dummy integer.  */
-static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0 };
+/* The maximum number of NOPs needed to fill delay slots.  */
+#define MAX_DELAY_NOPS 2
 
-/* Non-zero if prev_insn is valid.  */
-static int prev_insn_valid;
+/* The maximum number of NOPs needed for any purpose.  */
+#define MAX_NOPS 4
 
-/* The frag for the previous instruction.  */
-static struct frag *prev_insn_frag;
+/* A list of previous instructions, with index 0 being the most recent.
+   We need to look back MAX_NOPS instructions when filling delay slots
+   or working around processor errata.  We need to look back one
+   instruction further if we're thinking about using history[0] to
+   fill a branch delay slot.  */
+static struct mips_cl_insn history[1 + MAX_NOPS];
 
-/* The offset into prev_insn_frag for the previous instruction.  */
-static long prev_insn_where;
+/* Nop instructions used by emit_nop.  */
+static struct mips_cl_insn nop_insn, mips16_nop_insn;
 
-/* The reloc type for the previous instruction, if any.  */
-static bfd_reloc_code_real_type prev_insn_reloc_type[3];
-
-/* The reloc for the previous instruction, if any.  */
-static fixS *prev_insn_fixp[3];
-
-/* Non-zero if the previous instruction was in a delay slot.  */
-static int prev_insn_is_delay_slot;
-
-/* Non-zero if the previous instruction was in a .set noreorder.  */
-static int prev_insn_unreordered;
-
-/* Non-zero if the previous instruction uses an extend opcode (if
-   mips16).  */
-static int prev_insn_extended;
-
-/* Non-zero if the previous previous instruction was in a .set
-   noreorder.  */
-static int prev_prev_insn_unreordered;
+/* The appropriate nop for the current mode.  */
+#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)
 
 /* If this is set, it points to a frag holding nop instructions which
    were inserted before the start of a noreorder section.  If those
@@ -625,8 +688,29 @@ static const unsigned int mips16_to_32_r
   16, 17, 2, 3, 4, 5, 6, 7
 };
 
+/* Classifies the kind of instructions we're interested in when
+   implementing -mfix-vr4120.  */
+enum fix_vr4120_class {
+  FIX_VR4120_MACC,
+  FIX_VR4120_DMACC,
+  FIX_VR4120_MULT,
+  FIX_VR4120_DMULT,
+  FIX_VR4120_DIV,
+  FIX_VR4120_MTHILO,
+  NUM_FIX_VR4120_CLASSES
+};
+
+/* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
+   there must be at least one other instruction between an instruction
+   of type X and an instruction of type Y.  */
+static unsigned int vr4120_conflicts[NUM_FIX_VR4120_CLASSES];
+
+/* True if -mfix-vr4120 is in force.  */
 static int mips_fix_vr4120;
 
+/* ...likewise -mfix-vr4130.  */
+static int mips_fix_vr4130;
+
 /* We don't relax branches by default, since this causes us to expand
    `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
    fail to compute the offset before expanding the macro to the most
@@ -820,6 +904,41 @@ static int mips_relax_branch;
   (((x) &~ (offsetT) 0x7fff) == 0					\
    || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
 
+/* Is the given value a zero-extended 32-bit value?  Or a negated one?  */
+#define IS_ZEXT_32BIT_NUM(x)						\
+  (((x) &~ (offsetT) 0xffffffff) == 0					\
+   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
+
+/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in
+   VALUE << SHIFT.  VALUE is evaluated exactly once.  */
+#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \
+  (STRUCT) = (((STRUCT) & ~((MASK) << (SHIFT))) \
+	      | (((VALUE) & (MASK)) << (SHIFT)))
+
+/* Extract bits MASK << SHIFT from STRUCT and shift them right
+   SHIFT places.  */
+#define EXTRACT_BITS(STRUCT, MASK, SHIFT) \
+  (((STRUCT) >> (SHIFT)) & (MASK))
+
+/* Change INSN's opcode so that the operand given by FIELD has value VALUE.
+   INSN is a mips_cl_insn structure and VALUE is evaluated exactly once.
+
+   include/opcode/mips.h specifies operand fields using the macros
+   OP_MASK_<FIELD> and OP_SH_<FIELD>.  The MIPS16 equivalents start
+   with "MIPS16OP" instead of "OP".  */
+#define INSERT_OPERAND(FIELD, INSN, VALUE) \
+  INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)
+#define MIPS16_INSERT_OPERAND(FIELD, INSN, VALUE) \
+  INSERT_BITS ((INSN).insn_opcode, VALUE, \
+		MIPS16OP_MASK_##FIELD, MIPS16OP_SH_##FIELD)
+
+/* Extract the operand given by FIELD from mips_cl_insn INSN.  */
+#define EXTRACT_OPERAND(FIELD, INSN) \
+  EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)
+#define MIPS16_EXTRACT_OPERAND(FIELD, INSN) \
+  EXTRACT_BITS ((INSN).insn_opcode, \
+		MIPS16OP_MASK_##FIELD, \
+		MIPS16OP_SH_##FIELD)
 
 /* Global variables used when generating relaxable macros.  See the
    comment above RELAX_ENCODE for more details about how relaxation
@@ -866,7 +985,7 @@ enum mips_regclass { MIPS_GR_REG, MIPS_F
 
 static void append_insn
   (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
-static void mips_no_prev_insn (int);
+static void mips_no_prev_insn (void);
 static void mips16_macro_build
   (expressionS *, const char *, const char *, va_list);
 static void load_register (int, expressionS *, int);
@@ -1092,8 +1211,6 @@ mips_target_format (void)
 {
   switch (OUTPUT_FLAVOR)
     {
-    case bfd_target_aout_flavour:
-      return target_big_endian ? "a.out-mips-big" : "a.out-mips-little";
     case bfd_target_ecoff_flavour:
       return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
     case bfd_target_coff_flavour:
@@ -1127,6 +1244,174 @@ mips_target_format (void)
     }
 }
 
+/* Return the length of instruction INSN.  */
+
+static inline unsigned int
+insn_length (const struct mips_cl_insn *insn)
+{
+  if (!mips_opts.mips16)
+    return 4;
+  return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
+}
+
+/* Initialise INSN from opcode entry MO.  Leave its position unspecified.  */
+
+static void
+create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
+{
+  size_t i;
+
+  insn->insn_mo = mo;
+  insn->use_extend = FALSE;
+  insn->extend = 0;
+  insn->insn_opcode = mo->match;
+  insn->frag = NULL;
+  insn->where = 0;
+  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
+    insn->fixp[i] = NULL;
+  insn->fixed_p = (mips_opts.noreorder > 0);
+  insn->noreorder_p = (mips_opts.noreorder > 0);
+  insn->mips16_absolute_jump_p = 0;
+}
+
+/* Install INSN at the location specified by its "frag" and "where" fields.  */
+
+static void
+install_insn (const struct mips_cl_insn *insn)
+{
+  char *f = insn->frag->fr_literal + insn->where;
+  if (!mips_opts.mips16)
+    md_number_to_chars (f, insn->insn_opcode, 4);
+  else if (insn->mips16_absolute_jump_p)
+    {
+      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
+      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
+    }
+  else
+    {
+      if (insn->use_extend)
+	{
+	  md_number_to_chars (f, 0xf000 | insn->extend, 2);
+	  f += 2;
+	}
+      md_number_to_chars (f, insn->insn_opcode, 2);
+    }
+}
+
+/* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
+   and install the opcode in the new location.  */
+
+static void
+move_insn (struct mips_cl_insn *insn, fragS *frag, long where)
+{
+  size_t i;
+
+  insn->frag = frag;
+  insn->where = where;
+  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
+    if (insn->fixp[i] != NULL)
+      {
+	insn->fixp[i]->fx_frag = frag;
+	insn->fixp[i]->fx_where = where;
+      }
+  install_insn (insn);
+}
+
+/* Add INSN to the end of the output.  */
+
+static void
+add_fixed_insn (struct mips_cl_insn *insn)
+{
+  char *f = frag_more (insn_length (insn));
+  move_insn (insn, frag_now, f - frag_now->fr_literal);
+}
+
+/* Start a variant frag and move INSN to the start of the variant part,
+   marking it as fixed.  The other arguments are as for frag_var.  */
+
+static void
+add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var,
+		  relax_substateT subtype, symbolS *symbol, offsetT offset)
+{
+  frag_grow (max_chars);
+  move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal);
+  insn->fixed_p = 1;
+  frag_var (rs_machine_dependent, max_chars, var,
+	    subtype, symbol, offset, NULL);
+}
+
+/* Insert N copies of INSN into the history buffer, starting at
+   position FIRST.  Neither FIRST nor N need to be clipped.  */
+
+static void
+insert_into_history (unsigned int first, unsigned int n,
+		     const struct mips_cl_insn *insn)
+{
+  if (mips_relax.sequence != 2)
+    {
+      unsigned int i;
+
+      for (i = ARRAY_SIZE (history); i-- > first;)
+	if (i >= first + n)
+	  history[i] = history[i - n];
+	else
+	  history[i] = *insn;
+    }
+}
+
+/* Emit a nop instruction, recording it in the history buffer.  */
+
+static void
+emit_nop (void)
+{
+  add_fixed_insn (NOP_INSN);
+  insert_into_history (0, 1, NOP_INSN);
+}
+
+/* Initialize vr4120_conflicts.  There is a bit of duplication here:
+   the idea is to make it obvious at a glance that each errata is
+   included.  */
+
+static void
+init_vr4120_conflicts (void)
+{
+#define CONFLICT(FIRST, SECOND) \
+    vr4120_conflicts[FIX_VR4120_##FIRST] |= 1 << FIX_VR4120_##SECOND
+
+  /* Errata 21 - [D]DIV[U] after [D]MACC */
+  CONFLICT (MACC, DIV);
+  CONFLICT (DMACC, DIV);
+
+  /* Errata 23 - Continuous DMULT[U]/DMACC instructions.  */
+  CONFLICT (DMULT, DMULT);
+  CONFLICT (DMULT, DMACC);
+  CONFLICT (DMACC, DMULT);
+  CONFLICT (DMACC, DMACC);
+
+  /* Errata 24 - MT{LO,HI} after [D]MACC */
+  CONFLICT (MACC, MTHILO);
+  CONFLICT (DMACC, MTHILO);
+
+  /* VR4181A errata MD(1): "If a MULT, MULTU, DMULT or DMULTU
+     instruction is executed immediately after a MACC or DMACC
+     instruction, the result of [either instruction] is incorrect."  */
+  CONFLICT (MACC, MULT);
+  CONFLICT (MACC, DMULT);
+  CONFLICT (DMACC, MULT);
+  CONFLICT (DMACC, DMULT);
+
+  /* VR4181A errata MD(4): "If a MACC or DMACC instruction is
+     executed immediately after a DMULT, DMULTU, DIV, DIVU,
+     DDIV or DDIVU instruction, the result of the MACC or
+     DMACC instruction is incorrect.".  */
+  CONFLICT (DMULT, MACC);
+  CONFLICT (DMULT, DMACC);
+  CONFLICT (DIV, MACC);
+  CONFLICT (DIV, DMACC);
+
+#undef CONFLICT
+}
+
 /* 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.  */
 
@@ -1137,6 +1422,13 @@ md_begin (void)
   int i = 0;
   int broken = 0;
 
+  if (mips_pic != NO_PIC)
+    {
+      if (g_switch_seen && g_switch_value != 0)
+	as_bad (_("-G may not be used in position-independent code"));
+      g_switch_value = 0;
+    }
+
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
@@ -1160,6 +1452,11 @@ md_begin (void)
 	    {
 	      if (!validate_mips_insn (&mips_opcodes[i]))
 		broken = 1;
+	      if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
+		{
+		  create_insn (&nop_insn, mips_opcodes + i);
+		  nop_insn.fixed_p = 1;
+		}
 	    }
 	  ++i;
 	}
@@ -1187,6 +1484,11 @@ md_begin (void)
 		       mips16_opcodes[i].name, mips16_opcodes[i].args);
 	      broken = 1;
 	    }
+	  if (mips16_nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
+	    {
+	      create_insn (&mips16_nop_insn, mips16_opcodes + i);
+	      mips16_nop_insn.fixed_p = 1;
+	    }
 	  ++i;
 	}
       while (i < bfd_mips16_num_opcodes
@@ -1239,7 +1541,7 @@ md_begin (void)
 				       &zero_address_frag));
     }
 
-  mips_no_prev_insn (FALSE);
+  mips_no_prev_insn ();
 
   mips_gprmask = 0;
   mips_cprmask[0] = 0;
@@ -1250,15 +1552,15 @@ md_begin (void)
   /* set the default alignment for the text section (2**2) */
   record_alignment (text_section, 2);
 
-  if (USE_GLOBAL_POINTER_OPT)
-    bfd_set_gp_size (stdoutput, g_switch_value);
+  bfd_set_gp_size (stdoutput, g_switch_value);
 
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
     {
       /* On a native system, sections must be aligned to 16 byte
-	 boundaries.  When configured for an embedded ELF target, we
+         boundaries.  When configured for an embedded ELF target, we
 	 don't bother.  */
-      if (strcmp (TARGET_OS, "elf") != 0)
+      if (strcmp (TARGET_OS, "elf") != 0
+	  && strcmp (TARGET_OS, "vxworks") != 0)
 	{
 	  (void) bfd_set_section_alignment (stdoutput, text_section, 4);
 	  (void) bfd_set_section_alignment (stdoutput, data_section, 4);
@@ -1346,6 +1648,9 @@ md_begin (void)
 
   if (! ECOFF_DEBUGGING)
     md_obj_begin ();
+
+  if (mips_fix_vr4120)
+    init_vr4120_conflicts ();
 }
 
 void
@@ -1408,8 +1713,8 @@ md_assemble (char *str)
 }
 
 /* Return true if the given relocation might need a matching %lo().
-   Note that R_MIPS_GOT16 relocations only need a matching %lo() when
-   applied to local symbols.  */
+   This is only "might" because SVR4 R_MIPS_GOT16 relocations only
+   need a matching %lo() when applied to local symbols.  */
 
 static inline bfd_boolean
 reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
@@ -1434,7 +1739,7 @@ fixup_has_matching_lo_p (fixS *fixp)
    of register.  */
 
 static int
-insn_uses_reg (struct mips_cl_insn *ip, unsigned int reg,
+insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
 	       enum mips_regclass class)
 {
   if (class == MIPS16_REG)
@@ -1459,38 +1764,33 @@ insn_uses_reg (struct mips_cl_insn *ip, 
 	 because there is no instruction that sets both $f0 and $f1
 	 and requires a delay.  */
       if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
-	  && ((((ip->insn_opcode >> OP_SH_FS) & OP_MASK_FS) &~(unsigned)1)
+	  && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
 	      == (reg &~ (unsigned) 1)))
 	return 1;
       if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
-	  && ((((ip->insn_opcode >> OP_SH_FT) & OP_MASK_FT) &~(unsigned)1)
+	  && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
 	      == (reg &~ (unsigned) 1)))
 	return 1;
     }
   else if (! mips_opts.mips16)
     {
       if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
-	  && ((ip->insn_opcode >> OP_SH_RS) & OP_MASK_RS) == reg)
+	  && EXTRACT_OPERAND (RS, *ip) == reg)
 	return 1;
       if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
-	  && ((ip->insn_opcode >> OP_SH_RT) & OP_MASK_RT) == reg)
+	  && EXTRACT_OPERAND (RT, *ip) == reg)
 	return 1;
     }
   else
     {
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
-	  && (mips16_to_32_reg_map[((ip->insn_opcode >> MIPS16OP_SH_RX)
-				    & MIPS16OP_MASK_RX)]
-	      == reg))
+	  && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
 	return 1;
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
-	  && (mips16_to_32_reg_map[((ip->insn_opcode >> MIPS16OP_SH_RY)
-				    & MIPS16OP_MASK_RY)]
-	      == reg))
+	  && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
 	return 1;
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
-	  && (mips16_to_32_reg_map[((ip->insn_opcode >> MIPS16OP_SH_MOVE32Z)
-				    & MIPS16OP_MASK_MOVE32Z)]
+	  && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
 	      == reg))
 	return 1;
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
@@ -1500,8 +1800,7 @@ insn_uses_reg (struct mips_cl_insn *ip, 
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
 	return 1;
       if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
-	  && ((ip->insn_opcode >> MIPS16OP_SH_REGR32)
-	      & MIPS16OP_MASK_REGR32) == reg)
+	  && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
 	return 1;
     }
 
@@ -1516,7 +1815,7 @@ reg_needs_delay (unsigned int reg)
 {
   unsigned long prev_pinfo;
 
-  prev_pinfo = prev_insn.insn_mo->pinfo;
+  prev_pinfo = history[0].insn_mo->pinfo;
   if (! mips_opts.noreorder
       && (((prev_pinfo & INSN_LOAD_MEMORY_DELAY)
 	   && ! gpr_interlocks)
@@ -1527,13 +1826,33 @@ reg_needs_delay (unsigned int reg)
 	 delay the use of general register rt for one instruction.  */
       /* Itbl support may require additional care here.  */
       know (prev_pinfo & INSN_WRITE_GPR_T);
-      if (reg == ((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT))
+      if (reg == EXTRACT_OPERAND (RT, history[0]))
 	return 1;
     }
 
   return 0;
 }
 
+/* Move all labels in insn_labels to the current insertion point.  */
+
+static void
+mips_move_labels (void)
+{
+  struct insn_label_list *l;
+  valueT val;
+
+  for (l = insn_labels; l != NULL; l = l->next)
+    {
+      assert (S_GET_SEGMENT (l->label) == now_seg);
+      symbol_set_frag (l->label, frag_now);
+      val = (valueT) frag_now_fix ();
+      /* mips16 text labels are stored as odd.  */
+      if (mips_opts.mips16)
+	++val;
+      S_SET_VALUE (l->label, val);
+    }
+}
+
 /* Mark instruction labels in mips16 mode.  This permits the linker to
    handle them specially, such as generating jalx instructions when
    needed.  We also make them odd for the duration of the assembly, in
@@ -1609,6 +1928,273 @@ relax_end (void)
   mips_relax.sequence = 0;
 }
 
+/* Classify an instruction according to the FIX_VR4120_* enumeration.
+   Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
+   by VR4120 errata.  */
+
+static unsigned int
+classify_vr4120_insn (const char *name)
+{
+  if (strncmp (name, "macc", 4) == 0)
+    return FIX_VR4120_MACC;
+  if (strncmp (name, "dmacc", 5) == 0)
+    return FIX_VR4120_DMACC;
+  if (strncmp (name, "mult", 4) == 0)
+    return FIX_VR4120_MULT;
+  if (strncmp (name, "dmult", 5) == 0)
+    return FIX_VR4120_DMULT;
+  if (strstr (name, "div"))
+    return FIX_VR4120_DIV;
+  if (strcmp (name, "mtlo") == 0 || strcmp (name, "mthi") == 0)
+    return FIX_VR4120_MTHILO;
+  return NUM_FIX_VR4120_CLASSES;
+}
+
+/* Return the number of instructions that must separate INSN1 and INSN2,
+   where INSN1 is the earlier instruction.  Return the worst-case value
+   for any INSN2 if INSN2 is null.  */
+
+static unsigned int
+insns_between (const struct mips_cl_insn *insn1,
+	       const struct mips_cl_insn *insn2)
+{
+  unsigned long pinfo1, pinfo2;
+
+  /* This function needs to know which pinfo flags are set for INSN2
+     and which registers INSN2 uses.  The former is stored in PINFO2 and
+     the latter is tested via INSN2_USES_REG.  If INSN2 is null, PINFO2
+     will have every flag set and INSN2_USES_REG will always return true.  */
+  pinfo1 = insn1->insn_mo->pinfo;
+  pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
+
+#define INSN2_USES_REG(REG, CLASS) \
+   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
+
+  /* For most targets, write-after-read dependencies on the HI and LO
+     registers must be separated by at least two instructions.  */
+  if (!hilo_interlocks)
+    {
+      if ((pinfo1 & INSN_READ_LO) && (pinfo2 & INSN_WRITE_LO))
+	return 2;
+      if ((pinfo1 & INSN_READ_HI) && (pinfo2 & INSN_WRITE_HI))
+	return 2;
+    }
+
+  /* If we're working around r7000 errata, there must be two instructions
+     between an mfhi or mflo and any instruction that uses the result.  */
+  if (mips_7000_hilo_fix
+      && MF_HILO_INSN (pinfo1)
+      && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
+    return 2;
+
+  /* If working around VR4120 errata, check for combinations that need
+     a single intervening instruction.  */
+  if (mips_fix_vr4120)
+    {
+      unsigned int class1, class2;
+
+      class1 = classify_vr4120_insn (insn1->insn_mo->name);
+      if (class1 != NUM_FIX_VR4120_CLASSES && vr4120_conflicts[class1] != 0)
+	{
+	  if (insn2 == NULL)
+	    return 1;
+	  class2 = classify_vr4120_insn (insn2->insn_mo->name);
+	  if (vr4120_conflicts[class1] & (1 << class2))
+	    return 1;
+	}
+    }
+
+  if (!mips_opts.mips16)
+    {
+      /* Check for GPR or coprocessor load delays.  All such delays
+	 are on the RT register.  */
+      /* Itbl support may require additional care here.  */
+      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
+	  || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
+	{
+	  know (pinfo1 & INSN_WRITE_GPR_T);
+	  if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
+	    return 1;
+	}
+
+      /* Check for generic coprocessor hazards.
+
+	 This case is not handled very well.  There is no special
+	 knowledge of CP0 handling, and the coprocessors other than
+	 the floating point unit are not distinguished at all.  */
+      /* Itbl support may require additional care here. FIXME!
+	 Need to modify this to include knowledge about
+	 user specified delays!  */
+      else if ((!cop_interlocks && (pinfo1 & INSN_COPROC_MOVE_DELAY))
+	       || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
+	{
+	  /* Handle cases where INSN1 writes to a known general coprocessor
+	     register.  There must be a one instruction delay before INSN2
+	     if INSN2 reads that register, otherwise no delay is needed.  */
+	  if (pinfo1 & INSN_WRITE_FPR_T)
+	    {
+	      if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
+		return 1;
+	    }
+	  else if (pinfo1 & INSN_WRITE_FPR_S)
+	    {
+	      if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
+		return 1;
+	    }
+	  else
+	    {
+	      /* Read-after-write dependencies on the control registers
+		 require a two-instruction gap.  */
+	      if ((pinfo1 & INSN_WRITE_COND_CODE)
+		  && (pinfo2 & INSN_READ_COND_CODE))
+		return 2;
+
+	      /* We don't know exactly what INSN1 does.  If INSN2 is
+		 also a coprocessor instruction, assume there must be
+		 a one instruction gap.  */
+	      if (pinfo2 & INSN_COP)
+		return 1;
+	    }
+	}
+
+      /* Check for read-after-write dependencies on the coprocessor
+	 control registers in cases where INSN1 does not need a general
+	 coprocessor delay.  This means that INSN1 is a floating point
+	 comparison instruction.  */
+      /* Itbl support may require additional care here.  */
+      else if (!cop_interlocks
+	       && (pinfo1 & INSN_WRITE_COND_CODE)
+	       && (pinfo2 & INSN_READ_COND_CODE))
+	return 1;
+    }
+
+#undef INSN2_USES_REG
+
+  return 0;
+}
+
+/* Return the number of nops that would be needed to work around the
+   VR4130 mflo/mfhi errata if instruction INSN immediately followed
+   the MAX_VR4130_NOPS instructions described by HISTORY.  */
+
+static int
+nops_for_vr4130 (const struct mips_cl_insn *history,
+		 const struct mips_cl_insn *insn)
+{
+  int i, j, reg;
+
+  /* Check if the instruction writes to HI or LO.  MTHI and MTLO
+     are not affected by the errata.  */
+  if (insn != 0
+      && ((insn->insn_mo->pinfo & (INSN_WRITE_HI | INSN_WRITE_LO)) == 0
+	  || strcmp (insn->insn_mo->name, "mtlo") == 0
+	  || strcmp (insn->insn_mo->name, "mthi") == 0))
+    return 0;
+
+  /* Search for the first MFLO or MFHI.  */
+  for (i = 0; i < MAX_VR4130_NOPS; i++)
+    if (!history[i].noreorder_p && MF_HILO_INSN (history[i].insn_mo->pinfo))
+      {
+	/* Extract the destination register.  */
+	if (mips_opts.mips16)
+	  reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
+	else
+	  reg = EXTRACT_OPERAND (RD, history[i]);
+
+	/* No nops are needed if INSN reads that register.  */
+	if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
+	  return 0;
+
+	/* ...or if any of the intervening instructions do.  */
+	for (j = 0; j < i; j++)
+	  if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
+	    return 0;
+
+	return MAX_VR4130_NOPS - i;
+      }
+  return 0;
+}
+
+/* Return the number of nops that would be needed if instruction INSN
+   immediately followed the MAX_NOPS instructions given by HISTORY,
+   where HISTORY[0] is the most recent instruction.  If INSN is null,
+   return the worse-case number of nops for any instruction.  */
+
+static int
+nops_for_insn (const struct mips_cl_insn *history,
+	       const struct mips_cl_insn *insn)
+{
+  int i, nops, tmp_nops;
+
+  nops = 0;
+  for (i = 0; i < MAX_DELAY_NOPS; i++)
+    if (!history[i].noreorder_p)
+      {
+	tmp_nops = insns_between (history + i, insn) - i;
+	if (tmp_nops > nops)
+	  nops = tmp_nops;
+      }
+
+  if (mips_fix_vr4130)
+    {
+      tmp_nops = nops_for_vr4130 (history, insn);
+      if (tmp_nops > nops)
+	nops = tmp_nops;
+    }
+
+  return nops;
+}
+
+/* The variable arguments provide NUM_INSNS extra instructions that
+   might be added to HISTORY.  Return the largest number of nops that
+   would be needed after the extended sequence.  */
+
+static int
+nops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
+{
+  va_list args;
+  struct mips_cl_insn buffer[MAX_NOPS];
+  struct mips_cl_insn *cursor;
+  int nops;
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list