public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11]
@ 2005-03-08 14:39 Richard Sandiford
  2005-03-08 14:42 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Richard Sandiford
  2005-03-08 19:06 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Eric Christopher
  0 siblings, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 14:39 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 34396 bytes --]

This is the first of a series of patches to work around the VR4133
errata described in the attachment.  Briefly, we need to look for cases
where an mflo or mfhi is followed by a multiplication or division and
where there is a gap of less than 4 instructions between them.

It's difficult to handle this errata within the current gas infrastructure
because everything is set up for inserting either one or two nops.
Specifically, gas keeps a lot of information about the last instruction
in global prev_insn* variables, and a limited amount of information
about the last-but-one instruction in prev_prev_insn*.  Extending this
approach to -mfix-vr4130 would have meant adding prev_prev_prev_insn*
and prev_prev_prev_prev_insn*, and I didn't really want to do that. ;)

Instead, I've tried to provide a more flexible (and hopefully cleaner)
nop-insertion infrastructure.  The main changes are to:

  (1) reduce code duplication
  (2) remove the hard-coded limit of 2 nops and
  (3) use a history array instead of a bunch of separate global variables.

As an added bonus, these patches allow gas to fill coprocessor delay
slots for !cop_interlocks, something that it can't currently do due
to potential ctc hazards:

	      /* If the branch reads the condition codes, we don't
		 even try to swap, because in the sequence
		   ctc1 $X,$31
		   INSN
		   INSN
		   bc1t LABEL
		 we can not swap, and I don't feel like handling that
		 case.  */
	      || (! mips_opts.mips16
		  && (pinfo & INSN_READ_COND_CODE)
		  && ! cop_interlocks)

The complete set of changes is quite big and difficult to follow, so
I've tried my best to split it up.  Most of the patches should make
sense as stand-alone improvements, but unfortunately, one or two will
leave a bit of ugliness lying around for later patches to clean up.
The first patch is an example of this....

----------------------------------------------------------------

This first patch just introduces the history array.  It mechanically
replaces all references to prev_insn* with references to history[0] and
all references to prev_prev_insn* with references to history[1].

The size of the history buffer is hard-coded at 2 for now; this will
be cleaned up by a later patch.  There is also some redundancy in the
information we keep; this too will be cleaned up later.  The point of
this patch is to be as simple and mechanical as possible.

One of the main decisions was whether to introduce a new type
for storing the history or whether to add fields to the existing
mips_cl_insn structure (the one used by append_insn to communicate
with its callers).  I've gone for the latter here.  Hopefully this
choice becomes more obvious after patch 5, which introduces a new
set of functions for manipulating instructions.  Until then,
each valid field of the old structure must be copied explicitly,
but this really is just temporary ugliness.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.h (mips_cl_insn): Move definition to...
	* config/tc-mips.c (mips_cl_insn): ...here.  Add new fields:
	frag, where, fixp, reloc_type, valid_p, noreorder_p, delay_slot_p
	and extended_p.
	(history): New variable.
	(prev_insn, prev_prev_insn, prev_insn_valid, prev_insn_frag)
	(prev_insn_where, prev_insn_reloc_type, prev_insn_fixp)
	(prev_insn_is_delay_slot, prev_insn_unreordered, prev_insn_extended)
	(prev_prev_insn_unreordered): Delete.
	(reg_needs_delay, append_insn, mips_no_prev_insn, mips_emit_delays)
	(macro_start): Replace uses of prev_insn* with the equivalent history[]
	field.

diff -urpN gas.1/config/tc-mips.h gas/config/tc-mips.h
--- gas.1/config/tc-mips.h	2005-03-08 08:59:34.929057103 +0000
+++ gas/config/tc-mips.h	2005-03-08 09:07:40.524922786 +0000
@@ -79,15 +79,6 @@ enum mips_pic_level
 
 extern enum mips_pic_level mips_pic;
 
-struct mips_cl_insn
-{
-  unsigned long insn_opcode;
-  const struct mips_opcode *insn_mo;
-  /* The next two fields are used when generating mips16 code.  */
-  bfd_boolean use_extend;
-  unsigned short extend;
-};
-
 extern int tc_get_register (int frame);
 
 #define md_after_parse_args() mips_after_parse_args()
diff -urpN gas.1/config/tc-mips.c gas/config/tc-mips.c
--- gas.1/config/tc-mips.c	2005-03-08 09:06:54.215895139 +0000
+++ gas/config/tc-mips.c	2005-03-08 09:07:40.562917062 +0000
@@ -119,6 +119,50 @@ 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];
+
+  /* The reloc types associated with the instruction.  */
+  bfd_reloc_code_real_type reloc_type[3];
+
+  /* True if this entry describes a real instruction.  */
+  unsigned int valid_p : 1;
+
+  /* True if this instruction occured in a .set noreorder block.  */
+  unsigned int noreorder_p : 1;
+
+  /* True if this instruction corresponds to an assembler-filled
+     delay slot.  Always false if noreorder_p.  */
+  unsigned int delay_slot_p : 1;
+
+  /* True for extended mips16 instructions.  */
+  unsigned int extended_p : 1;
+};
+
 /* The ABI to use.  */
 enum mips_abi_level
 {
@@ -520,45 +564,13 @@ 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;
+/* A list of previous instructions, with index 0 being the most recent.  */
+static struct mips_cl_insn history[2];
 
-/* The instruction before prev_insn.  */
-static struct mips_cl_insn prev_prev_insn;
-
-/* If we don't want information for prev_insn or prev_prev_insn, we
+/* If we don't want information for a history[] entry, we
    point the insn_mo field at this dummy integer.  */
 static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0, 0 };
 
-/* Non-zero if prev_insn is valid.  */
-static int prev_insn_valid;
-
-/* The frag for the previous instruction.  */
-static struct frag *prev_insn_frag;
-
-/* The offset into prev_insn_frag for the previous instruction.  */
-static long prev_insn_where;
-
-/* 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;
-
 /* If this is set, it points to a frag holding nop instructions which
    were inserted before the start of a noreorder section.  If those
    nops turn out to be unnecessary, the size of the frag can be
@@ -1515,7 +1527,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)
@@ -1526,7 +1538,7 @@ 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 == ((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT))
 	return 1;
     }
 
@@ -1627,7 +1639,7 @@ append_insn (struct mips_cl_insn *ip, ex
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
 
-  prev_pinfo = prev_insn.insn_mo->pinfo;
+  prev_pinfo = history[0].insn_mo->pinfo;
   pinfo = ip->insn_mo->pinfo;
 
   if (mips_relax.sequence != 2
@@ -1676,7 +1688,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  know (prev_pinfo & INSN_WRITE_GPR_T);
 	  if (mips_optimize == 0
 	      || insn_uses_reg (ip,
-				((prev_insn.insn_opcode >> OP_SH_RT)
+				((history[0].insn_opcode >> OP_SH_RT)
 				 & OP_MASK_RT),
 				MIPS_GR_REG))
 	    ++nops;
@@ -1705,7 +1717,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	    {
 	      if (mips_optimize == 0
 		  || insn_uses_reg (ip,
-				    ((prev_insn.insn_opcode >> OP_SH_FT)
+				    ((history[0].insn_opcode >> OP_SH_FT)
 				     & OP_MASK_FT),
 				    MIPS_FP_REG))
 		++nops;
@@ -1714,7 +1726,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	    {
 	      if (mips_optimize == 0
 		  || insn_uses_reg (ip,
-				    ((prev_insn.insn_opcode >> OP_SH_FS)
+				    ((history[0].insn_opcode >> OP_SH_FS)
 				     & OP_MASK_FS),
 				    MIPS_FP_REG))
 		++nops;
@@ -1758,7 +1770,7 @@ append_insn (struct mips_cl_insn *ip, ex
 
       else if (mips_7000_hilo_fix
 	       && MF_HILO_INSN (prev_pinfo)
-	       && insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
+	       && insn_uses_reg (ip, ((history[0].insn_opcode >> OP_SH_RD)
 				      & OP_MASK_RD),
 				 MIPS_GR_REG))
 	{
@@ -1771,8 +1783,8 @@ append_insn (struct mips_cl_insn *ip, ex
 	 insert one nop.  */
 
       else if (mips_7000_hilo_fix
-	       && MF_HILO_INSN (prev_prev_insn.insn_opcode)
-	       && insn_uses_reg (ip, ((prev_prev_insn.insn_opcode >> OP_SH_RD)
+	       && MF_HILO_INSN (history[1].insn_opcode)
+	       && insn_uses_reg (ip, ((history[1].insn_opcode >> OP_SH_RD)
                                        & OP_MASK_RD),
                                     MIPS_GR_REG))
 
@@ -1805,7 +1817,7 @@ append_insn (struct mips_cl_insn *ip, ex
 		       || (pinfo & MIPS16_INSN_BRANCH)))
 	    ++nops;
 	}
-      else if (prev_insn.insn_mo->pinfo & INSN_READ_HI)
+      else if (history[0].insn_mo->pinfo & INSN_READ_HI)
 	{
 	  /* The previous instruction reads the HI register; if the
 	     current instruction writes to the HI register, we must
@@ -1831,7 +1843,7 @@ append_insn (struct mips_cl_insn *ip, ex
       /* If the previous instruction was in a noreorder section, then
          we don't want to insert the nop after all.  */
       /* Itbl support may require additional care here.  */
-      if (prev_insn_unreordered)
+      if (history[0].noreorder_p)
 	nops = 0;
 
       /* There are two cases which require two intervening
@@ -1843,15 +1855,15 @@ append_insn (struct mips_cl_insn *ip, ex
 	 instruction, we must check for these cases compared to the
 	 instruction previous to the previous instruction.  */
       if ((! mips_opts.mips16
-	   && (prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
-	   && (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
+	   && (history[1].insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
+	   && (history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
 	   && (pinfo & INSN_READ_COND_CODE)
 	   && ! cop_interlocks)
-	  || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
+	  || ((history[1].insn_mo->pinfo & INSN_READ_LO)
 	      && (pinfo & INSN_WRITE_LO)
 	      && ! (hilo_interlocks
 		    || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT))))
-	  || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
+	  || ((history[1].insn_mo->pinfo & INSN_READ_HI)
 	      && (pinfo & INSN_WRITE_HI)
 	      && ! (hilo_interlocks
 		    || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))))
@@ -1859,19 +1871,19 @@ append_insn (struct mips_cl_insn *ip, ex
       else
 	prev_prev_nop = 0;
 
-      if (prev_prev_insn_unreordered)
+      if (history[1].noreorder_p)
 	prev_prev_nop = 0;
 
       if (prev_prev_nop && nops == 0)
 	++nops;
 
-      if (mips_fix_vr4120 && prev_insn.insn_mo->name)
+      if (mips_fix_vr4120 && history[0].insn_mo->name)
 	{
 	  /* We're out of bits in pinfo, so we must resort to string
 	     ops here.  Shortcuts are selected based on opcodes being
 	     limited to the VR4120 instruction set.  */
 	  int min_nops = 0;
-	  const char *pn = prev_insn.insn_mo->name;
+	  const char *pn = history[0].insn_mo->name;
 	  const char *tn = ip->insn_mo->name;
 	  if (strncmp (pn, "macc", 4) == 0
 	      || strncmp (pn, "dmacc", 5) == 0)
@@ -2024,8 +2036,8 @@ append_insn (struct mips_cl_insn *ip, ex
 #endif
 
   /* Record the frag type before frag_var.  */
-  if (prev_insn_frag)
-    prev_insn_frag_type = prev_insn_frag->fr_type;
+  if (history[0].frag)
+    prev_insn_frag_type = history[0].frag->fr_type;
 
   if (address_expr
       && *reloc_type == BFD_RELOC_16_PCREL_S2
@@ -2064,7 +2076,7 @@ append_insn (struct mips_cl_insn *ip, ex
 					 mips16_small, mips16_ext,
 					 (prev_pinfo
 					  & INSN_UNCOND_BRANCH_DELAY),
-					 (*prev_insn_reloc_type
+					 (*history[0].reloc_type
 					  == BFD_RELOC_MIPS16_JMP)),
 		    make_expr_symbol (address_expr), 0, NULL);
     }
@@ -2348,10 +2360,10 @@ append_insn (struct mips_cl_insn *ip, ex
 	      || nops != 0
 	      /* If we don't even know the previous insn, we can not
 		 swap.  */
-	      || ! prev_insn_valid
+	      || ! history[0].valid_p
 	      /* If the previous insn is already in a branch delay
 		 slot, then we can not swap.  */
-	      || prev_insn_is_delay_slot
+	      || history[0].delay_slot_p
 	      /* If the previous previous insn was in a .set
 		 noreorder, we can't swap.  Actually, the MIPS
 		 assembler will swap in this situation.  However, gcc
@@ -2364,11 +2376,11 @@ append_insn (struct mips_cl_insn *ip, ex
 		 in which we can not swap the bne and INSN.  If gcc is
 		 not configured -with-gnu-as, it does not output the
 		 .set pseudo-ops.  We don't have to check
-		 prev_insn_unreordered, because prev_insn_valid will
+		 history[0].noreorder_p, because history[0].valid_p will
 		 be 0 in that case.  We don't want to use
-		 prev_prev_insn_valid, because we do want to be able
+		 history[1].valid_p, because we do want to be able
 		 to swap at the start of a function.  */
-	      || prev_prev_insn_unreordered
+	      || history[1].noreorder_p
 	      /* If the branch is itself the target of a branch, we
 		 can not swap.  We cheat on this; all we check for is
 		 whether there is a label on this instruction.  If
@@ -2428,31 +2440,31 @@ append_insn (struct mips_cl_insn *ip, ex
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_T)
 		  && insn_uses_reg (ip,
-				    ((prev_insn.insn_opcode >> OP_SH_RT)
+				    ((history[0].insn_opcode >> OP_SH_RT)
 				     & OP_MASK_RT),
 				    MIPS_GR_REG))
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_D)
 		  && insn_uses_reg (ip,
-				    ((prev_insn.insn_opcode >> OP_SH_RD)
+				    ((history[0].insn_opcode >> OP_SH_RD)
 				     & OP_MASK_RD),
 				    MIPS_GR_REG))
 	      || (mips_opts.mips16
 		  && (((prev_pinfo & MIPS16_INSN_WRITE_X)
 		       && insn_uses_reg (ip,
-					 ((prev_insn.insn_opcode
+					 ((history[0].insn_opcode
 					   >> MIPS16OP_SH_RX)
 					  & MIPS16OP_MASK_RX),
 					 MIPS16_REG))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
 			  && insn_uses_reg (ip,
-					    ((prev_insn.insn_opcode
+					    ((history[0].insn_opcode
 					      >> MIPS16OP_SH_RY)
 					     & MIPS16OP_MASK_RY),
 					    MIPS16_REG))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
 			  && insn_uses_reg (ip,
-					    ((prev_insn.insn_opcode
+					    ((history[0].insn_opcode
 					      >> MIPS16OP_SH_RZ)
 					     & MIPS16OP_MASK_RZ),
 					    MIPS16_REG))
@@ -2462,8 +2474,8 @@ append_insn (struct mips_cl_insn *ip, ex
 			  && insn_uses_reg (ip, RA, MIPS_GR_REG))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
 			  && insn_uses_reg (ip,
-					    MIPS16OP_EXTRACT_REG32R (prev_insn.
-								     insn_opcode),
+					    MIPS16OP_EXTRACT_REG32R
+					      (history[0].insn_opcode),
 					    MIPS_GR_REG))))
 	      /* If the branch writes a register that the previous
 		 instruction sets, we can not swap (we know that
@@ -2471,54 +2483,54 @@ append_insn (struct mips_cl_insn *ip, ex
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_T)
 		  && (((pinfo & INSN_WRITE_GPR_D)
-		       && (((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT)
+		       && (((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT)
 			   == ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
 		      || ((pinfo & INSN_WRITE_GPR_31)
-			  && (((prev_insn.insn_opcode >> OP_SH_RT)
+			  && (((history[0].insn_opcode >> OP_SH_RT)
 			       & OP_MASK_RT)
 			      == RA))))
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_D)
 		  && (((pinfo & INSN_WRITE_GPR_D)
-		       && (((prev_insn.insn_opcode >> OP_SH_RD) & OP_MASK_RD)
+		       && (((history[0].insn_opcode >> OP_SH_RD) & OP_MASK_RD)
 			   == ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
 		      || ((pinfo & INSN_WRITE_GPR_31)
-			  && (((prev_insn.insn_opcode >> OP_SH_RD)
+			  && (((history[0].insn_opcode >> OP_SH_RD)
 			       & OP_MASK_RD)
 			      == RA))))
 	      || (mips_opts.mips16
 		  && (pinfo & MIPS16_INSN_WRITE_31)
 		  && ((prev_pinfo & MIPS16_INSN_WRITE_31)
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
-			  && (MIPS16OP_EXTRACT_REG32R (prev_insn.insn_opcode)
+			  && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
 			      == RA))))
 	      /* If the branch writes a register that the previous
 		 instruction reads, we can not swap (we know that
 		 branches only write to RD or to $31).  */
 	      || (! mips_opts.mips16
 		  && (pinfo & INSN_WRITE_GPR_D)
-		  && insn_uses_reg (&prev_insn,
+		  && insn_uses_reg (&history[0],
 				    ((ip->insn_opcode >> OP_SH_RD)
 				     & OP_MASK_RD),
 				    MIPS_GR_REG))
 	      || (! mips_opts.mips16
 		  && (pinfo & INSN_WRITE_GPR_31)
-		  && insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
+		  && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
 	      || (mips_opts.mips16
 		  && (pinfo & MIPS16_INSN_WRITE_31)
-		  && insn_uses_reg (&prev_insn, RA, MIPS_GR_REG))
+		  && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
 	      /* If the previous previous instruction has a load
 		 delay, and sets a register that the branch reads, we
 		 can not swap.  */
 	      || (! mips_opts.mips16
               /* Itbl support may require additional care here.  */
-		  && (((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
+		  && (((history[1].insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
 		       && ! cop_interlocks)
-		      || ((prev_prev_insn.insn_mo->pinfo
+		      || ((history[1].insn_mo->pinfo
 			   & INSN_LOAD_MEMORY_DELAY)
 			  && ! gpr_interlocks))
 		  && insn_uses_reg (ip,
-				    ((prev_prev_insn.insn_opcode >> OP_SH_RT)
+				    ((history[1].insn_opcode >> OP_SH_RT)
 				     & OP_MASK_RT),
 				    MIPS_GR_REG))
 	      /* If one instruction sets a condition code and the
@@ -2533,11 +2545,11 @@ append_insn (struct mips_cl_insn *ip, ex
 		  && (prev_pinfo & MIPS16_INSN_READ_PC))
 	      /* If the previous instruction was extended, we can not
                  swap.  */
-	      || (mips_opts.mips16 && prev_insn_extended)
+	      || (mips_opts.mips16 && history[0].extended_p)
 	      /* If the previous instruction had a fixup in mips16
                  mode, we can not swap.  This normally means that the
                  previous instruction was a 4 byte branch anyhow.  */
-	      || (mips_opts.mips16 && prev_insn_fixp[0])
+	      || (mips_opts.mips16 && history[0].fixp[0])
 	      /* If the previous instruction is a sync, sync.l, or
 		 sync.p, we can not swap.  */
 	      || (prev_pinfo & INSN_SYNC))
@@ -2550,8 +2562,11 @@ append_insn (struct mips_cl_insn *ip, ex
 	      if (mips_relax.sequence)
 		mips_relax.sizes[mips_relax.sequence - 1] += 4;
 	      /* Update the previous insn information.  */
-	      prev_prev_insn = *ip;
-	      prev_insn.insn_mo = &dummy_opcode;
+	      history[1].insn_mo = ip->insn_mo;
+	      history[1].use_extend = ip->use_extend;
+	      history[1].extend = ip->extend;
+	      history[1].insn_opcode = ip->insn_opcode;
+	      history[0].insn_mo = &dummy_opcode;
 	    }
 	  else
 	    {
@@ -2561,7 +2576,7 @@ append_insn (struct mips_cl_insn *ip, ex
 		  char *prev_f;
 		  char temp[4];
 
-		  prev_f = prev_insn_frag->fr_literal + prev_insn_where;
+		  prev_f = history[0].frag->fr_literal + history[0].where;
 		  if (!relaxed_branch)
 		    {
 		      /* If this is not a relaxed branch, then just
@@ -2580,31 +2595,31 @@ append_insn (struct mips_cl_insn *ip, ex
 			 into the space freed by the moved instruction.  */
 		      f = frag_more (4);
 		      memcpy (f, prev_f, 4);
-		      prev_insn_frag->fr_fix -= 4;
-		      if (prev_insn_frag->fr_type == rs_machine_dependent)
-			memmove (prev_f, prev_f + 4, prev_insn_frag->fr_var);
+		      history[0].frag->fr_fix -= 4;
+		      if (history[0].frag->fr_type == rs_machine_dependent)
+			memmove (prev_f, prev_f + 4, history[0].frag->fr_var);
 		    }
 
-		  if (prev_insn_fixp[0])
+		  if (history[0].fixp[0])
 		    {
-		      prev_insn_fixp[0]->fx_frag = frag_now;
-		      prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal;
+		      history[0].fixp[0]->fx_frag = frag_now;
+		      history[0].fixp[0]->fx_where = f - frag_now->fr_literal;
 		    }
-		  if (prev_insn_fixp[1])
+		  if (history[0].fixp[1])
 		    {
-		      prev_insn_fixp[1]->fx_frag = frag_now;
-		      prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal;
+		      history[0].fixp[1]->fx_frag = frag_now;
+		      history[0].fixp[1]->fx_where = f - frag_now->fr_literal;
 		    }
-		  if (prev_insn_fixp[2])
+		  if (history[0].fixp[2])
 		    {
-		      prev_insn_fixp[2]->fx_frag = frag_now;
-		      prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal;
+		      history[0].fixp[2]->fx_frag = frag_now;
+		      history[0].fixp[2]->fx_where = f - frag_now->fr_literal;
 		    }
-		  if (prev_insn_fixp[0] && HAVE_NEWABI
-		      && prev_insn_frag != frag_now
-		      && (prev_insn_fixp[0]->fx_r_type
+		  if (history[0].fixp[0] && HAVE_NEWABI
+		      && history[0].frag != frag_now
+		      && (history[0].fixp[0]->fx_r_type
 			  == BFD_RELOC_MIPS_GOT_DISP
-			  || (prev_insn_fixp[0]->fx_r_type
+			  || (history[0].fixp[0]->fx_r_type
 			      == BFD_RELOC_MIPS_CALL16)))
 		    {
 		      /* To avoid confusion in tc_gen_reloc, we must
@@ -2617,21 +2632,21 @@ append_insn (struct mips_cl_insn *ip, ex
 		    {
 		      if (fixp[0])
 			{
-			  fixp[0]->fx_frag = prev_insn_frag;
-			  fixp[0]->fx_where = prev_insn_where;
+			  fixp[0]->fx_frag = history[0].frag;
+			  fixp[0]->fx_where = history[0].where;
 			}
 		      if (fixp[1])
 			{
-			  fixp[1]->fx_frag = prev_insn_frag;
-			  fixp[1]->fx_where = prev_insn_where;
+			  fixp[1]->fx_frag = history[0].frag;
+			  fixp[1]->fx_where = history[0].where;
 			}
 		      if (fixp[2])
 			{
-			  fixp[2]->fx_frag = prev_insn_frag;
-			  fixp[2]->fx_where = prev_insn_where;
+			  fixp[2]->fx_frag = history[0].frag;
+			  fixp[2]->fx_where = history[0].where;
 			}
 		    }
-		  else if (prev_insn_frag->fr_type == rs_machine_dependent)
+		  else if (history[0].frag->fr_type == rs_machine_dependent)
 		    {
 		      if (fixp[0])
 			fixp[0]->fx_where -= 4;
@@ -2646,10 +2661,10 @@ append_insn (struct mips_cl_insn *ip, ex
 		  char *prev_f;
 		  char temp[2];
 
-		  assert (prev_insn_fixp[0] == NULL);
-		  assert (prev_insn_fixp[1] == NULL);
-		  assert (prev_insn_fixp[2] == NULL);
-		  prev_f = prev_insn_frag->fr_literal + prev_insn_where;
+		  assert (history[0].fixp[0] == NULL);
+		  assert (history[0].fixp[1] == NULL);
+		  assert (history[0].fixp[2] == NULL);
+		  prev_f = history[0].frag->fr_literal + history[0].where;
 		  memcpy (temp, prev_f, 2);
 		  memcpy (prev_f, f, 2);
 		  if (*reloc_type != BFD_RELOC_MIPS16_JMP)
@@ -2664,42 +2679,45 @@ append_insn (struct mips_cl_insn *ip, ex
 		    }
 		  if (fixp[0])
 		    {
-		      fixp[0]->fx_frag = prev_insn_frag;
-		      fixp[0]->fx_where = prev_insn_where;
+		      fixp[0]->fx_frag = history[0].frag;
+		      fixp[0]->fx_where = history[0].where;
 		    }
 		  if (fixp[1])
 		    {
-		      fixp[1]->fx_frag = prev_insn_frag;
-		      fixp[1]->fx_where = prev_insn_where;
+		      fixp[1]->fx_frag = history[0].frag;
+		      fixp[1]->fx_where = history[0].where;
 		    }
 		  if (fixp[2])
 		    {
-		      fixp[2]->fx_frag = prev_insn_frag;
-		      fixp[2]->fx_where = prev_insn_where;
+		      fixp[2]->fx_frag = history[0].frag;
+		      fixp[2]->fx_where = history[0].where;
 		    }
 		}
 
-	      /* Update the previous insn information; leave prev_insn
+	      /* Update the previous insn information; leave history[0]
 		 unchanged.  */
-	      prev_prev_insn = *ip;
+	      history[1].insn_mo = ip->insn_mo;
+	      history[1].use_extend = ip->use_extend;
+	      history[1].extend = ip->extend;
+	      history[1].insn_opcode = ip->insn_opcode;
 	    }
-	  prev_insn_is_delay_slot = 1;
+	  history[0].delay_slot_p = 1;
 
 	  /* If that was an unconditional branch, forget the previous
 	     insn information.  */
 	  if (pinfo & INSN_UNCOND_BRANCH_DELAY)
 	    {
-	      prev_prev_insn.insn_mo = &dummy_opcode;
-	      prev_insn.insn_mo = &dummy_opcode;
+	      history[1].insn_mo = &dummy_opcode;
+	      history[0].insn_mo = &dummy_opcode;
 	    }
 
-	  prev_insn_fixp[0] = NULL;
-	  prev_insn_fixp[1] = NULL;
-	  prev_insn_fixp[2] = NULL;
-	  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
-	  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
-	  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
-	  prev_insn_extended = 0;
+	  history[0].fixp[0] = NULL;
+	  history[0].fixp[1] = NULL;
+	  history[0].fixp[2] = NULL;
+	  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
+	  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
+	  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+	  history[0].extended_p = 0;
 	}
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
 	{
@@ -2709,60 +2727,77 @@ append_insn (struct mips_cl_insn *ip, ex
 	     the next instruction.  */
 	  emit_nop ();
 	  /* Update the previous insn information.  */
-	  prev_prev_insn = *ip;
-	  prev_insn.insn_mo = &dummy_opcode;
-	  prev_insn_fixp[0] = NULL;
-	  prev_insn_fixp[1] = NULL;
-	  prev_insn_fixp[2] = NULL;
-	  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
-	  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
-	  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
-	  prev_insn_extended = 0;
-	  prev_insn_is_delay_slot = 1;
+	  history[1].insn_mo = ip->insn_mo;
+	  history[1].use_extend = ip->use_extend;
+	  history[1].extend = ip->extend;
+	  history[1].insn_opcode = ip->insn_opcode;
+	  history[0].insn_mo = &dummy_opcode;
+	  history[0].fixp[0] = NULL;
+	  history[0].fixp[1] = NULL;
+	  history[0].fixp[2] = NULL;
+	  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
+	  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
+	  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+	  history[0].extended_p = 0;
+	  history[0].delay_slot_p = 1;
 	}
       else
 	{
 	  /* Update the previous insn information.  */
 	  if (nops > 0)
-	    prev_prev_insn.insn_mo = &dummy_opcode;
+	    history[1].insn_mo = &dummy_opcode;
 	  else
-	    prev_prev_insn = prev_insn;
-	  prev_insn = *ip;
+	    {
+	      history[1].insn_mo = history[0].insn_mo;
+	      history[1].use_extend = history[0].use_extend;
+	      history[1].extend = history[0].extend;
+	      history[1].insn_opcode = history[0].insn_opcode;
+	    }
+	  history[0].insn_mo = ip->insn_mo;
+	  history[0].use_extend = ip->use_extend;
+	  history[0].extend = ip->extend;
+	  history[0].insn_opcode = ip->insn_opcode;
 
 	  /* Any time we see a branch, we always fill the delay slot
 	     immediately; since this insn is not a branch, we know it
 	     is not in a delay slot.  */
-	  prev_insn_is_delay_slot = 0;
+	  history[0].delay_slot_p = 0;
 
-	  prev_insn_fixp[0] = fixp[0];
-	  prev_insn_fixp[1] = fixp[1];
-	  prev_insn_fixp[2] = fixp[2];
-	  prev_insn_reloc_type[0] = reloc_type[0];
-	  prev_insn_reloc_type[1] = reloc_type[1];
-	  prev_insn_reloc_type[2] = reloc_type[2];
+	  history[0].fixp[0] = fixp[0];
+	  history[0].fixp[1] = fixp[1];
+	  history[0].fixp[2] = fixp[2];
+	  history[0].reloc_type[0] = reloc_type[0];
+	  history[0].reloc_type[1] = reloc_type[1];
+	  history[0].reloc_type[2] = reloc_type[2];
 	  if (mips_opts.mips16)
-	    prev_insn_extended = (ip->use_extend
-				  || *reloc_type > BFD_RELOC_UNUSED);
+	    history[0].extended_p = (ip->use_extend
+				     || *reloc_type > BFD_RELOC_UNUSED);
 	}
 
-      prev_prev_insn_unreordered = prev_insn_unreordered;
-      prev_insn_unreordered = 0;
-      prev_insn_frag = frag_now;
-      prev_insn_where = f - frag_now->fr_literal;
-      prev_insn_valid = 1;
+      history[1].noreorder_p = history[0].noreorder_p;
+      history[0].noreorder_p = 0;
+      history[0].frag = frag_now;
+      history[0].where = f - frag_now->fr_literal;
+      history[0].valid_p = 1;
     }
   else if (mips_relax.sequence != 2)
     {
       /* We need to record a bit of information even when we are not
          reordering, in order to determine the base address for mips16
          PC relative relocs.  */
-      prev_prev_insn = prev_insn;
-      prev_insn = *ip;
-      prev_insn_reloc_type[0] = reloc_type[0];
-      prev_insn_reloc_type[1] = reloc_type[1];
-      prev_insn_reloc_type[2] = reloc_type[2];
-      prev_prev_insn_unreordered = prev_insn_unreordered;
-      prev_insn_unreordered = 1;
+      history[1].insn_mo = history[0].insn_mo;
+      history[1].use_extend = history[0].use_extend;
+      history[1].extend = history[0].extend;
+      history[1].insn_opcode = history[0].insn_opcode;
+      history[0].insn_mo = ip->insn_mo;
+      history[0].use_extend = ip->use_extend;
+      history[0].extend = ip->extend;
+      history[0].insn_opcode = ip->insn_opcode;
+      history[0].reloc_type[0] = reloc_type[0];
+      history[0].reloc_type[1] = reloc_type[1];
+      history[0].reloc_type[2] = reloc_type[2];
+      history[1].noreorder_p = history[0].noreorder_p;
+      history[0].noreorder_p = 1;
     }
 
   /* We just output an insn, so the next one doesn't have a label.  */
@@ -2778,21 +2813,21 @@ mips_no_prev_insn (int preserve)
 {
   if (! preserve)
     {
-      prev_insn.insn_mo = &dummy_opcode;
-      prev_prev_insn.insn_mo = &dummy_opcode;
+      history[0].insn_mo = &dummy_opcode;
+      history[1].insn_mo = &dummy_opcode;
       prev_nop_frag = NULL;
       prev_nop_frag_holds = 0;
       prev_nop_frag_required = 0;
       prev_nop_frag_since = 0;
     }
-  prev_insn_valid = 0;
-  prev_insn_is_delay_slot = 0;
-  prev_insn_unreordered = 0;
-  prev_insn_extended = 0;
-  prev_insn_reloc_type[0] = BFD_RELOC_UNUSED;
-  prev_insn_reloc_type[1] = BFD_RELOC_UNUSED;
-  prev_insn_reloc_type[2] = BFD_RELOC_UNUSED;
-  prev_prev_insn_unreordered = 0;
+  history[0].valid_p = 0;
+  history[0].delay_slot_p = 0;
+  history[0].noreorder_p = 0;
+  history[0].extended_p = 0;
+  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
+  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
+  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+  history[1].noreorder_p = 0;
   mips_clear_insn_labels ();
 }
 
@@ -2811,51 +2846,51 @@ mips_emit_delays (bfd_boolean insns)
 
       nops = 0;
       if ((! mips_opts.mips16
-	   && ((prev_insn.insn_mo->pinfo
+	   && ((history[0].insn_mo->pinfo
 		& (INSN_LOAD_COPROC_DELAY
 		   | INSN_COPROC_MOVE_DELAY
 		   | INSN_WRITE_COND_CODE))
 	       && ! cop_interlocks))
 	  || (! hilo_interlocks
-	      && (prev_insn.insn_mo->pinfo
+	      && (history[0].insn_mo->pinfo
 		  & (INSN_READ_LO
 		     | INSN_READ_HI)))
 	  || (! mips_opts.mips16
-	      && (prev_insn.insn_mo->pinfo & INSN_LOAD_MEMORY_DELAY)
+	      && (history[0].insn_mo->pinfo & INSN_LOAD_MEMORY_DELAY)
 	      && ! gpr_interlocks)
 	  || (! mips_opts.mips16
-	      && (prev_insn.insn_mo->pinfo & INSN_COPROC_MEMORY_DELAY)
+	      && (history[0].insn_mo->pinfo & INSN_COPROC_MEMORY_DELAY)
 	      && ! cop_mem_interlocks))
 	{
 	  /* Itbl support may require additional care here.  */
 	  ++nops;
 	  if ((! mips_opts.mips16
-	       && ((prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
+	       && ((history[0].insn_mo->pinfo & INSN_WRITE_COND_CODE)
 		   && ! cop_interlocks))
 	      || (! hilo_interlocks
-		  && ((prev_insn.insn_mo->pinfo & INSN_READ_HI)
-		      || (prev_insn.insn_mo->pinfo & INSN_READ_LO))))
+		  && ((history[0].insn_mo->pinfo & INSN_READ_HI)
+		      || (history[0].insn_mo->pinfo & INSN_READ_LO))))
 	    ++nops;
 
-	  if (prev_insn_unreordered)
+	  if (history[0].noreorder_p)
 	    nops = 0;
 	}
       else if ((! mips_opts.mips16
-		&& ((prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
+		&& ((history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
 		    && ! cop_interlocks))
 	       || (! hilo_interlocks
-		   && ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
-		       || (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
+		   && ((history[1].insn_mo->pinfo & INSN_READ_HI)
+		       || (history[1].insn_mo->pinfo & INSN_READ_LO))))
 	{
 	  /* Itbl support may require additional care here.  */
-	  if (! prev_prev_insn_unreordered)
+	  if (! history[1].noreorder_p)
 	    ++nops;
 	}
 
-      if (mips_fix_vr4120 && prev_insn.insn_mo->name)
+      if (mips_fix_vr4120 && history[0].insn_mo->name)
 	{
 	  int min_nops = 0;
-	  const char *pn = prev_insn.insn_mo->name;
+	  const char *pn = history[0].insn_mo->name;
 	  if (strncmp (pn, "macc", 4) == 0
 	      || strncmp (pn, "dmacc", 5) == 0
 	      || strncmp (pn, "dmult", 5) == 0
@@ -2920,7 +2955,7 @@ macro_start (void)
 {
   memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
   mips_macro_warning.delay_slot_p = (mips_opts.noreorder
-				     && (prev_insn.insn_mo->pinfo
+				     && (history[0].insn_mo->pinfo
 					 & (INSN_UNCOND_BRANCH_DELAY
 					    | INSN_COND_BRANCH_DELAY
 					    | INSN_COND_BRANCH_LIKELY)) != 0);


[-- Attachment #2: VR4133_Restriction15_2.txt --]
[-- Type: text/plain, Size: 2308 bytes --]

<VR4133 Problem> ===========================================================

[Restriction 15] CPU (4)

When "mult/div/macc" instruction (NOTE1) follows "mflo/mfhi" instruction, 
the "mult/div/macc" result is mistaken for "mflo/mfhi" one in the following
conditions.

NOTE1 MULT/MULTU/DMULT/DMULTU, DIV/DIVU/DDIV/DDIVU, 
      MACC/DMACC, MACCU/DMACCU, MACCHI/DMACCHI, 
      MACCHIU/DMACCHIU, MACCS/DMACCS, MACCUS/DMACCUS, 
      MACCHIS/DMACCHIS, MACCHIUS/DMACCHIUS

  Conditions:
       - The instruction steps are less than 4 between "mflo/mfhi" and 
         "mult/div/macc".
       - The "mflo/mfhi" execution is stalled or held during executing
         the load/store instructions located in right before the mflo/mfhi
         (within 2 instructions).


<Relevant instruction sequence>
The following instruction sequence causes the problem.
---------------------------
all load/store instruction
 (0 or 1 instruction)
mflo/mfhi
 (3 or less instructions)
mult/div/macc NOTE1, NOTE2

NOTE2 The following case is the exception and doesn't cause
      the problem.
   - The case which the result of mflo/mfhi is used for 
     the source of mult/div/macc
---------------------------


<Possible work-arounds>

Either one of the following four can be the work-around.

(1) Place 4 or more instructions between mflo/mfhi and mult/div/macc.

ex.
│@│@mflo  s2
    nop
    nop
    nop
    nop
    mult  s1,v1

(2) Place the dummy instruction which generates the source interlock right after
    the mflo/mfhi.

ex1.
    mflo  s2
    or    zero,zero,s2
    mult  s1,v1

ex2.
│@│@mflo  s2
    addu  zero,zero,s2
    mult  s1,v1

(3) Don't put load/store instruction before mflo/mfhi within 2 instructions.
    Or don't put mflo/mfhi instruction after load/store instruction within 
    2 instructions. 

ex.
    lw  s0,0(a0)
    nop
    nop
    mflo  s2
    mult  s1,v1

(4) Use the MACC type of instructions which have destination instead of
    "mflo/mfhi" instructions.

ex1.
    mtlo zero
    macc  s2,a1,v0   /* alternative to mflo */
    mult  s1,v1

ex2.
    mtlo zero
    mthi zero
    macchi  s2,a1,v0 /* alternative to mfhi */
    mult  s1,v1

<End> ===========================================================

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11]
  2005-03-08 14:39 Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Richard Sandiford
@ 2005-03-08 14:42 ` Richard Sandiford
  2005-03-08 14:46   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Richard Sandiford
  2005-03-08 19:07   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Eric Christopher
  2005-03-08 19:06 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 14:42 UTC (permalink / raw)
  To: binutils

gas used to store the entire contents of the append_insn reloc_type[]
argument in prev_insn_reloc_type.  It turns out that element 0 was only
used used to detect MIPS16 absolute jumps and elements 1 and 2 weren't
used at all.

Now that we're using a structure to record the insn history, we might as
well use a bitfield to record the mips16 condition.  Doing this makes the
code simpler and shaves three ints off the size of mips_cl_insn.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.c (mips_cl_insn): Replace reloc_type array with
	a single mips16_absolute_jump_p bit.
	(append_insn): Adjust accordingly.

diff -urpN gas.2/config/tc-mips.c gas/config/tc-mips.c
--- gas.2/config/tc-mips.c	2005-03-08 09:07:40.562917062 +0000
+++ gas/config/tc-mips.c	2005-03-08 10:04:27.514029340 +0000
@@ -146,9 +146,6 @@ struct mips_cl_insn
   /* The relocs associated with the instruction, if any.  */
   fixS *fixp[3];
 
-  /* The reloc types associated with the instruction.  */
-  bfd_reloc_code_real_type reloc_type[3];
-
   /* True if this entry describes a real instruction.  */
   unsigned int valid_p : 1;
 
@@ -161,6 +158,9 @@ struct mips_cl_insn
 
   /* True for extended mips16 instructions.  */
   unsigned int extended_p : 1;
+
+  /* True for mips16 instructions that jump to an absolute address.  */
+  unsigned int mips16_absolute_jump_p : 1;
 };
 
 /* The ABI to use.  */
@@ -2076,8 +2076,7 @@ append_insn (struct mips_cl_insn *ip, ex
 					 mips16_small, mips16_ext,
 					 (prev_pinfo
 					  & INSN_UNCOND_BRANCH_DELAY),
-					 (*history[0].reloc_type
-					  == BFD_RELOC_MIPS16_JMP)),
+					 history[0].mips16_absolute_jump_p),
 		    make_expr_symbol (address_expr), 0, NULL);
     }
   else if (mips_opts.mips16
@@ -2714,9 +2713,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].fixp[0] = NULL;
 	  history[0].fixp[1] = NULL;
 	  history[0].fixp[2] = NULL;
-	  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
-	  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
-	  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+	  history[0].mips16_absolute_jump_p = 0;
 	  history[0].extended_p = 0;
 	}
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
@@ -2735,9 +2732,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].fixp[0] = NULL;
 	  history[0].fixp[1] = NULL;
 	  history[0].fixp[2] = NULL;
-	  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
-	  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
-	  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+	  history[0].mips16_absolute_jump_p = 0;
 	  history[0].extended_p = 0;
 	  history[0].delay_slot_p = 1;
 	}
@@ -2766,9 +2761,8 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].fixp[0] = fixp[0];
 	  history[0].fixp[1] = fixp[1];
 	  history[0].fixp[2] = fixp[2];
-	  history[0].reloc_type[0] = reloc_type[0];
-	  history[0].reloc_type[1] = reloc_type[1];
-	  history[0].reloc_type[2] = reloc_type[2];
+	  history[0].mips16_absolute_jump_p = (reloc_type[0]
+					       == BFD_RELOC_MIPS16_JMP);
 	  if (mips_opts.mips16)
 	    history[0].extended_p = (ip->use_extend
 				     || *reloc_type > BFD_RELOC_UNUSED);
@@ -2793,9 +2787,8 @@ append_insn (struct mips_cl_insn *ip, ex
       history[0].use_extend = ip->use_extend;
       history[0].extend = ip->extend;
       history[0].insn_opcode = ip->insn_opcode;
-      history[0].reloc_type[0] = reloc_type[0];
-      history[0].reloc_type[1] = reloc_type[1];
-      history[0].reloc_type[2] = reloc_type[2];
+      history[0].mips16_absolute_jump_p = (reloc_type[0]
+					   == BFD_RELOC_MIPS16_JMP);
       history[1].noreorder_p = history[0].noreorder_p;
       history[0].noreorder_p = 1;
     }
@@ -2824,9 +2817,7 @@ mips_no_prev_insn (int preserve)
   history[0].delay_slot_p = 0;
   history[0].noreorder_p = 0;
   history[0].extended_p = 0;
-  history[0].reloc_type[0] = BFD_RELOC_UNUSED;
-  history[0].reloc_type[1] = BFD_RELOC_UNUSED;
-  history[0].reloc_type[2] = BFD_RELOC_UNUSED;
+  history[0].mips16_absolute_jump_p = 0;
   history[1].noreorder_p = 0;
   mips_clear_insn_labels ();
 }

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11]
  2005-03-08 14:42 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Richard Sandiford
@ 2005-03-08 14:46   ` Richard Sandiford
  2005-03-08 14:50     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Richard Sandiford
  2005-03-08 19:08     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Eric Christopher
  2005-03-08 19:07   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 14:46 UTC (permalink / raw)
  To: binutils

Three of the old prev_insn properties -- prev_insn_valid,
prev_insn_delay_slot and prev_insn_extended -- were only used to detect
cases where a previous instruction could not be used to fill a delay slot.
As far as the rest of these patches are concerned, it would be much easier
if we just had a single flag to say "this instruction cannot be moved".

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard




	* config/tc-mips.c (mips_cl_insn): Replace valid_p, delay_slot_p
	and extended_p fields with a single fixed_p field.
	(append_insn, mips_no_prev_insn): Adjust accordingly.

diff -urpN gas.3/config/tc-mips.c gas/config/tc-mips.c
--- gas.3/config/tc-mips.c	2005-03-08 10:04:27.514029340 +0000
+++ gas/config/tc-mips.c	2005-03-08 10:12:01.923312861 +0000
@@ -146,19 +146,12 @@ struct mips_cl_insn
   /* The relocs associated with the instruction, if any.  */
   fixS *fixp[3];
 
-  /* True if this entry describes a real instruction.  */
-  unsigned int valid_p : 1;
+  /* 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 if this instruction corresponds to an assembler-filled
-     delay slot.  Always false if noreorder_p.  */
-  unsigned int delay_slot_p : 1;
-
-  /* True for extended mips16 instructions.  */
-  unsigned int extended_p : 1;
-
   /* True for mips16 instructions that jump to an absolute address.  */
   unsigned int mips16_absolute_jump_p : 1;
 };
@@ -2357,12 +2350,9 @@ append_insn (struct mips_cl_insn *ip, ex
 	      /* If we had to emit any NOP instructions, then we
 		 already know we can not swap.  */
 	      || nops != 0
-	      /* If we don't even know the previous insn, we can not
-		 swap.  */
-	      || ! history[0].valid_p
-	      /* If the previous insn is already in a branch delay
-		 slot, then we can not swap.  */
-	      || history[0].delay_slot_p
+	      /* We can't swap if the previous instruction's position
+		 is fixed.  */
+	      || history[0].fixed_p
 	      /* If the previous previous insn was in a .set
 		 noreorder, we can't swap.  Actually, the MIPS
 		 assembler will swap in this situation.  However, gcc
@@ -2374,11 +2364,7 @@ append_insn (struct mips_cl_insn *ip, ex
 		   bne	$4,$0,foo
 		 in which we can not swap the bne and INSN.  If gcc is
 		 not configured -with-gnu-as, it does not output the
-		 .set pseudo-ops.  We don't have to check
-		 history[0].noreorder_p, because history[0].valid_p will
-		 be 0 in that case.  We don't want to use
-		 history[1].valid_p, because we do want to be able
-		 to swap at the start of a function.  */
+		 .set pseudo-ops.  */
 	      || history[1].noreorder_p
 	      /* If the branch is itself the target of a branch, we
 		 can not swap.  We cheat on this; all we check for is
@@ -2542,9 +2528,6 @@ append_insn (struct mips_cl_insn *ip, ex
                  swap.  */
 	      || (mips_opts.mips16
 		  && (prev_pinfo & MIPS16_INSN_READ_PC))
-	      /* If the previous instruction was extended, we can not
-                 swap.  */
-	      || (mips_opts.mips16 && history[0].extended_p)
 	      /* If the previous instruction had a fixup in mips16
                  mode, we can not swap.  This normally means that the
                  previous instruction was a 4 byte branch anyhow.  */
@@ -2700,7 +2683,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	      history[1].extend = ip->extend;
 	      history[1].insn_opcode = ip->insn_opcode;
 	    }
-	  history[0].delay_slot_p = 1;
+	  history[0].fixed_p = 1;
 
 	  /* If that was an unconditional branch, forget the previous
 	     insn information.  */
@@ -2714,7 +2697,6 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].fixp[1] = NULL;
 	  history[0].fixp[2] = NULL;
 	  history[0].mips16_absolute_jump_p = 0;
-	  history[0].extended_p = 0;
 	}
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
 	{
@@ -2733,8 +2715,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].fixp[1] = NULL;
 	  history[0].fixp[2] = NULL;
 	  history[0].mips16_absolute_jump_p = 0;
-	  history[0].extended_p = 0;
-	  history[0].delay_slot_p = 1;
+	  history[0].fixed_p = 1;
 	}
       else
 	{
@@ -2752,27 +2733,20 @@ append_insn (struct mips_cl_insn *ip, ex
 	  history[0].use_extend = ip->use_extend;
 	  history[0].extend = ip->extend;
 	  history[0].insn_opcode = ip->insn_opcode;
-
-	  /* Any time we see a branch, we always fill the delay slot
-	     immediately; since this insn is not a branch, we know it
-	     is not in a delay slot.  */
-	  history[0].delay_slot_p = 0;
-
+	  history[0].fixed_p = (mips_opts.mips16
+				&& (ip->use_extend
+				    || *reloc_type > BFD_RELOC_UNUSED));
 	  history[0].fixp[0] = fixp[0];
 	  history[0].fixp[1] = fixp[1];
 	  history[0].fixp[2] = fixp[2];
 	  history[0].mips16_absolute_jump_p = (reloc_type[0]
 					       == BFD_RELOC_MIPS16_JMP);
-	  if (mips_opts.mips16)
-	    history[0].extended_p = (ip->use_extend
-				     || *reloc_type > BFD_RELOC_UNUSED);
 	}
 
       history[1].noreorder_p = history[0].noreorder_p;
       history[0].noreorder_p = 0;
       history[0].frag = frag_now;
       history[0].where = f - frag_now->fr_literal;
-      history[0].valid_p = 1;
     }
   else if (mips_relax.sequence != 2)
     {
@@ -2791,6 +2765,7 @@ append_insn (struct mips_cl_insn *ip, ex
 					   == BFD_RELOC_MIPS16_JMP);
       history[1].noreorder_p = history[0].noreorder_p;
       history[0].noreorder_p = 1;
+      history[0].fixed_p = 1;
     }
 
   /* We just output an insn, so the next one doesn't have a label.  */
@@ -2813,10 +2788,8 @@ mips_no_prev_insn (int preserve)
       prev_nop_frag_required = 0;
       prev_nop_frag_since = 0;
     }
-  history[0].valid_p = 0;
-  history[0].delay_slot_p = 0;
+  history[0].fixed_p = 1;
   history[0].noreorder_p = 0;
-  history[0].extended_p = 0;
   history[0].mips16_absolute_jump_p = 0;
   history[1].noreorder_p = 0;
   mips_clear_insn_labels ();

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11]
  2005-03-08 14:46   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Richard Sandiford
@ 2005-03-08 14:50     ` Richard Sandiford
  2005-03-08 14:56       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Richard Sandiford
  2005-03-08 19:09       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Eric Christopher
  2005-03-08 19:08     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 14:50 UTC (permalink / raw)
  To: binutils

This patch defines some convenience macros for inserting and extracting
operands and converts the existing gas code to use them.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard



	* config/tc-mips.c (INSERT_BITS, EXTRACT_BITS, INSERT_OPERAND)
	(EXTRACT_OPERAND, MIPS16_INSERT_OPERAND, MIPS16_EXTRACT_OPERAND): New.
	(insn_uses_reg, reg_needs_delay, append_insn, macro_build)
	(mips16_macro_build, macro_build_lui, mips16_macro, mips_ip)
	(mips16_ip): Use the new macros instead of explicit masks and shifts.

diff -urpN gas.4/config/tc-mips.c gas/config/tc-mips.c
--- gas.4/config/tc-mips.c	2005-03-08 10:12:01.923312861 +0000
+++ gas/config/tc-mips.c	2005-03-08 10:19:44.469831745 +0000
@@ -824,6 +824,36 @@ static int mips_relax_branch;
   (((x) &~ (offsetT) 0x7fff) == 0					\
    || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
 
+/* 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)
 \f
 /* Global variables used when generating relaxable macros.  See the
    comment above RELAX_ENCODE for more details about how relaxation
@@ -1463,38 +1493,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)
@@ -1504,8 +1529,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;
     }
 
@@ -1531,7 +1555,7 @@ 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 == ((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT))
+      if (reg == EXTRACT_OPERAND (RT, history[0]))
 	return 1;
     }
 
@@ -1680,9 +1704,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  /* Itbl support may require additional care here.  */
 	  know (prev_pinfo & INSN_WRITE_GPR_T);
 	  if (mips_optimize == 0
-	      || insn_uses_reg (ip,
-				((history[0].insn_opcode >> OP_SH_RT)
-				 & OP_MASK_RT),
+	      || insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
 				MIPS_GR_REG))
 	    ++nops;
 	}
@@ -1709,18 +1731,14 @@ append_insn (struct mips_cl_insn *ip, ex
 	  if (prev_pinfo & INSN_WRITE_FPR_T)
 	    {
 	      if (mips_optimize == 0
-		  || insn_uses_reg (ip,
-				    ((history[0].insn_opcode >> OP_SH_FT)
-				     & OP_MASK_FT),
+		  || insn_uses_reg (ip, EXTRACT_OPERAND (FT, history[0]),
 				    MIPS_FP_REG))
 		++nops;
 	    }
 	  else if (prev_pinfo & INSN_WRITE_FPR_S)
 	    {
 	      if (mips_optimize == 0
-		  || insn_uses_reg (ip,
-				    ((history[0].insn_opcode >> OP_SH_FS)
-				     & OP_MASK_FS),
+		  || insn_uses_reg (ip, EXTRACT_OPERAND (FS, history[0]),
 				    MIPS_FP_REG))
 		++nops;
 	    }
@@ -1763,8 +1781,7 @@ append_insn (struct mips_cl_insn *ip, ex
 
       else if (mips_7000_hilo_fix
 	       && MF_HILO_INSN (prev_pinfo)
-	       && insn_uses_reg (ip, ((history[0].insn_opcode >> OP_SH_RD)
-				      & OP_MASK_RD),
+	       && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
 				 MIPS_GR_REG))
 	{
 	  nops += 2;
@@ -1777,9 +1794,8 @@ append_insn (struct mips_cl_insn *ip, ex
 
       else if (mips_7000_hilo_fix
 	       && MF_HILO_INSN (history[1].insn_opcode)
-	       && insn_uses_reg (ip, ((history[1].insn_opcode >> OP_SH_RD)
-                                       & OP_MASK_RD),
-                                    MIPS_GR_REG))
+	       && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[1]),
+				 MIPS_GR_REG))
 
 	{
 	  ++nops;
@@ -2281,21 +2297,21 @@ append_insn (struct mips_cl_insn *ip, ex
   if (! mips_opts.mips16)
     {
       if (pinfo & INSN_WRITE_GPR_D)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD);
+	mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
       if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> OP_SH_RT) & OP_MASK_RT);
+	mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
       if (pinfo & INSN_READ_GPR_S)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> OP_SH_RS) & OP_MASK_RS);
+	mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
       if (pinfo & INSN_WRITE_GPR_31)
 	mips_gprmask |= 1 << RA;
       if (pinfo & INSN_WRITE_FPR_D)
-	mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FD) & OP_MASK_FD);
+	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
       if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
-	mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FS) & OP_MASK_FS);
+	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
       if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
-	mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FT) & OP_MASK_FT);
+	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
       if ((pinfo & INSN_READ_FPR_R) != 0)
-	mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FR) & OP_MASK_FR);
+	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
       if (pinfo & INSN_COP)
 	{
 	  /* We don't keep enough information to sort these cases out.
@@ -2309,14 +2325,11 @@ append_insn (struct mips_cl_insn *ip, ex
   else
     {
       if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
-	mips_gprmask |= 1 << ((ip->insn_opcode >> MIPS16OP_SH_RX)
-			      & MIPS16OP_MASK_RX);
+	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
       if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
-	mips_gprmask |= 1 << ((ip->insn_opcode >> MIPS16OP_SH_RY)
-			      & MIPS16OP_MASK_RY);
+	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
       if (pinfo & MIPS16_INSN_WRITE_Z)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> MIPS16OP_SH_RZ)
-			      & MIPS16OP_MASK_RZ);
+	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
       if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
 	mips_gprmask |= 1 << TREG;
       if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
@@ -2326,11 +2339,9 @@ append_insn (struct mips_cl_insn *ip, ex
       if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
 	mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
       if (pinfo & MIPS16_INSN_READ_Z)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> MIPS16OP_SH_MOVE32Z)
-			      & MIPS16OP_MASK_MOVE32Z);
+	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
       if (pinfo & MIPS16_INSN_READ_GPR_X)
-	mips_gprmask |= 1 << ((ip->insn_opcode >> MIPS16OP_SH_REGR32)
-			      & MIPS16OP_MASK_REGR32);
+	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
     }
 
   if (mips_relax.sequence != 2 && !mips_opts.noreorder)
@@ -2424,35 +2435,25 @@ append_insn (struct mips_cl_insn *ip, ex
 		 instruction sets, we can not swap.  */
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_T)
-		  && insn_uses_reg (ip,
-				    ((history[0].insn_opcode >> OP_SH_RT)
-				     & OP_MASK_RT),
+		  && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
 				    MIPS_GR_REG))
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_D)
-		  && insn_uses_reg (ip,
-				    ((history[0].insn_opcode >> OP_SH_RD)
-				     & OP_MASK_RD),
+		  && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
 				    MIPS_GR_REG))
 	      || (mips_opts.mips16
 		  && (((prev_pinfo & MIPS16_INSN_WRITE_X)
-		       && insn_uses_reg (ip,
-					 ((history[0].insn_opcode
-					   >> MIPS16OP_SH_RX)
-					  & MIPS16OP_MASK_RX),
-					 MIPS16_REG))
+		       && (insn_uses_reg
+			   (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
+			    MIPS16_REG)))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
-			  && insn_uses_reg (ip,
-					    ((history[0].insn_opcode
-					      >> MIPS16OP_SH_RY)
-					     & MIPS16OP_MASK_RY),
-					    MIPS16_REG))
+			  && (insn_uses_reg
+			      (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
+			       MIPS16_REG)))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
-			  && insn_uses_reg (ip,
-					    ((history[0].insn_opcode
-					      >> MIPS16OP_SH_RZ)
-					     & MIPS16OP_MASK_RZ),
-					    MIPS16_REG))
+			  && (insn_uses_reg
+			      (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
+			       MIPS16_REG)))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_T)
 			  && insn_uses_reg (ip, TREG, MIPS_GR_REG))
 		      || ((prev_pinfo & MIPS16_INSN_WRITE_31)
@@ -2468,21 +2469,17 @@ append_insn (struct mips_cl_insn *ip, ex
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_T)
 		  && (((pinfo & INSN_WRITE_GPR_D)
-		       && (((history[0].insn_opcode >> OP_SH_RT) & OP_MASK_RT)
-			   == ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
+		       && (EXTRACT_OPERAND (RT, history[0])
+			   == EXTRACT_OPERAND (RD, *ip)))
 		      || ((pinfo & INSN_WRITE_GPR_31)
-			  && (((history[0].insn_opcode >> OP_SH_RT)
-			       & OP_MASK_RT)
-			      == RA))))
+			  && EXTRACT_OPERAND (RT, history[0]) == RA)))
 	      || (! mips_opts.mips16
 		  && (prev_pinfo & INSN_WRITE_GPR_D)
 		  && (((pinfo & INSN_WRITE_GPR_D)
-		       && (((history[0].insn_opcode >> OP_SH_RD) & OP_MASK_RD)
-			   == ((ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD)))
+		       && (EXTRACT_OPERAND (RD, history[0])
+			   == EXTRACT_OPERAND (RD, *ip)))
 		      || ((pinfo & INSN_WRITE_GPR_31)
-			  && (((history[0].insn_opcode >> OP_SH_RD)
-			       & OP_MASK_RD)
-			      == RA))))
+			  && EXTRACT_OPERAND (RD, history[0]) == RA)))
 	      || (mips_opts.mips16
 		  && (pinfo & MIPS16_INSN_WRITE_31)
 		  && ((prev_pinfo & MIPS16_INSN_WRITE_31)
@@ -2495,8 +2492,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	      || (! mips_opts.mips16
 		  && (pinfo & INSN_WRITE_GPR_D)
 		  && insn_uses_reg (&history[0],
-				    ((ip->insn_opcode >> OP_SH_RD)
-				     & OP_MASK_RD),
+				    EXTRACT_OPERAND (RD, *ip),
 				    MIPS_GR_REG))
 	      || (! mips_opts.mips16
 		  && (pinfo & INSN_WRITE_GPR_31)
@@ -2514,9 +2510,7 @@ append_insn (struct mips_cl_insn *ip, ex
 		      || ((history[1].insn_mo->pinfo
 			   & INSN_LOAD_MEMORY_DELAY)
 			  && ! gpr_interlocks))
-		  && insn_uses_reg (ip,
-				    ((history[1].insn_opcode >> OP_SH_RT)
-				     & OP_MASK_RT),
+		  && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[1]),
 				    MIPS_GR_REG))
 	      /* If one instruction sets a condition code and the
                  other one uses a condition code, we can not swap.  */
@@ -3060,8 +3054,7 @@ macro_build (expressionS *ep, const char
 	    {
 	    case 'A':
 	    case 'E':
-	      insn.insn_opcode |= (va_arg (args, int)
-				   & OP_MASK_SHAMT) << OP_SH_SHAMT;
+	      INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
 	      continue;
 
 	    case 'B':
@@ -3070,8 +3063,7 @@ macro_build (expressionS *ep, const char
 		 in MSB form.  (When handling the instruction in the
 		 non-macro case, these arguments are sizes from which
 		 MSB values must be calculated.)  */
-	      insn.insn_opcode |= (va_arg (args, int)
-				   & OP_MASK_INSMSB) << OP_SH_INSMSB;
+	      INSERT_OPERAND (INSMSB, insn, va_arg (args, int));
 	      continue;
 
 	    case 'C':
@@ -3081,8 +3073,7 @@ macro_build (expressionS *ep, const char
 		 in MSBD form.  (When handling the instruction in the
 		 non-macro case, these arguments are sizes from which
 		 MSBD values must be calculated.)  */
-	      insn.insn_opcode |= (va_arg (args, int)
-				   & OP_MASK_EXTMSBD) << OP_SH_EXTMSBD;
+	      INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
 	      continue;
 
 	    default:
@@ -3093,66 +3084,66 @@ macro_build (expressionS *ep, const char
 	case 't':
 	case 'w':
 	case 'E':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_RT;
+	  INSERT_OPERAND (RT, insn, va_arg (args, int));
 	  continue;
 
 	case 'c':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE;
+	  INSERT_OPERAND (CODE, insn, va_arg (args, int));
 	  continue;
 
 	case 'T':
 	case 'W':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_FT;
+	  INSERT_OPERAND (FT, insn, va_arg (args, int));
 	  continue;
 
 	case 'd':
 	case 'G':
 	case 'K':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_RD;
+	  INSERT_OPERAND (RD, insn, va_arg (args, int));
 	  continue;
 
 	case 'U':
 	  {
 	    int tmp = va_arg (args, int);
 
-	    insn.insn_opcode |= tmp << OP_SH_RT;
-	    insn.insn_opcode |= tmp << OP_SH_RD;
+	    INSERT_OPERAND (RT, insn, tmp);
+	    INSERT_OPERAND (RD, insn, tmp);
 	    continue;
 	  }
 
 	case 'V':
 	case 'S':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_FS;
+	  INSERT_OPERAND (FS, insn, va_arg (args, int));
 	  continue;
 
 	case 'z':
 	  continue;
 
 	case '<':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_SHAMT;
+	  INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
 	  continue;
 
 	case 'D':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_FD;
+	  INSERT_OPERAND (FD, insn, va_arg (args, int));
 	  continue;
 
 	case 'B':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE20;
+	  INSERT_OPERAND (CODE20, insn, va_arg (args, int));
 	  continue;
 
 	case 'J':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE19;
+	  INSERT_OPERAND (CODE19, insn, va_arg (args, int));
 	  continue;
 
 	case 'q':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_CODE2;
+	  INSERT_OPERAND (CODE2, insn, va_arg (args, int));
 	  continue;
 
 	case 'b':
 	case 's':
 	case 'r':
 	case 'v':
-	  insn.insn_opcode |= va_arg (args, int) << OP_SH_RS;
+	  INSERT_OPERAND (RS, insn, va_arg (args, int));
 	  continue;
 
 	case 'i':
@@ -3264,20 +3255,20 @@ mips16_macro_build (expressionS *ep, con
 
 	case 'y':
 	case 'w':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_RY;
+	  MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
 	  continue;
 
 	case 'x':
 	case 'v':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_RX;
+	  MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
 	  continue;
 
 	case 'z':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_RZ;
+	  MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
 	  continue;
 
 	case 'Z':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_MOVE32Z;
+	  MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
 	  continue;
 
 	case '0':
@@ -3287,7 +3278,7 @@ mips16_macro_build (expressionS *ep, con
 	  continue;
 
 	case 'X':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_REGR32;
+	  MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
 	  continue;
 
 	case 'Y':
@@ -3333,7 +3324,7 @@ mips16_macro_build (expressionS *ep, con
 	  continue;
 
 	case '6':
-	  insn.insn_opcode |= va_arg (args, int) << MIPS16OP_SH_IMM6;
+	  MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
 	  continue;
 	}
 
@@ -3408,7 +3399,8 @@ macro_build_lui (expressionS *ep, int re
   assert (strcmp (name, insn.insn_mo->name) == 0);
   assert (strcmp (fmt, insn.insn_mo->args) == 0);
 
-  insn.insn_opcode = insn.insn_mo->match | (regnum << OP_SH_RT);
+  insn.insn_opcode = insn.insn_mo->match;
+  INSERT_OPERAND (RT, insn, regnum);
   if (*r == BFD_RELOC_UNUSED)
     {
       insn.insn_opcode |= high_expr.X_add_number;
@@ -7574,9 +7566,9 @@ mips16_macro (struct mips_cl_insn *ip)
 
   mask = ip->insn_mo->mask;
 
-  xreg = (ip->insn_opcode >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
-  yreg = (ip->insn_opcode >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY;
-  zreg = (ip->insn_opcode >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
+  xreg = MIPS16_EXTRACT_OPERAND (RX, *ip);
+  yreg = MIPS16_EXTRACT_OPERAND (RY, *ip);
+  zreg = MIPS16_EXTRACT_OPERAND (RZ, *ip);
 
   expr1.X_op = O_constant;
   expr1.X_op_symbol = NULL;
@@ -8050,19 +8042,19 @@ mips_ip (char *str, struct mips_cl_insn 
 		{
 		case 'r':
 		case 'v':
-		  ip->insn_opcode |= lastregno << OP_SH_RS;
+		  INSERT_OPERAND (RS, *ip, lastregno);
 		  continue;
 
 		case 'w':
-		  ip->insn_opcode |= lastregno << OP_SH_RT;
+		  INSERT_OPERAND (RT, *ip, lastregno);
 		  continue;
 
 		case 'W':
-		  ip->insn_opcode |= lastregno << OP_SH_FT;
+		  INSERT_OPERAND (FT, *ip, lastregno);
 		  continue;
 
 		case 'V':
-		  ip->insn_opcode |= lastregno << OP_SH_FS;
+		  INSERT_OPERAND (FS, *ip, lastregno);
 		  continue;
 		}
 	      break;
@@ -8107,8 +8099,7 @@ do_lsb:
 		      imm_expr.X_add_number = limlo;
 		    }
 		  lastpos = imm_expr.X_add_number;
-		  ip->insn_opcode |= (imm_expr.X_add_number
-				      & OP_MASK_SHAMT) << OP_SH_SHAMT;
+		  INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
 		  imm_expr.X_op = O_absent;
 		  s = expr_end;
 		  continue;
@@ -8139,8 +8130,8 @@ do_msb:
 			      (unsigned long) lastpos);
 		      imm_expr.X_add_number = limlo - lastpos;
 		    }
-		  ip->insn_opcode |= ((lastpos + imm_expr.X_add_number - 1)
-				      & OP_MASK_INSMSB) << OP_SH_INSMSB;
+		  INSERT_OPERAND (INSMSB, *ip,
+				 lastpos + imm_expr.X_add_number - 1);
 		  imm_expr.X_op = O_absent;
 		  s = expr_end;
 		  continue;
@@ -8175,8 +8166,7 @@ do_msbd:
 			      (unsigned long) lastpos);
 		      imm_expr.X_add_number = limlo - lastpos;
 		    }
-		  ip->insn_opcode |= ((imm_expr.X_add_number - 1)
-				      & OP_MASK_EXTMSBD) << OP_SH_EXTMSBD;
+		  INSERT_OPERAND (EXTMSBD, *ip, imm_expr.X_add_number - 1);
 		  imm_expr.X_op = O_absent;
 		  s = expr_end;
 		  continue;
@@ -8213,12 +8203,9 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > 31)
-		{
-		  as_warn (_("Improper shift amount (%lu)"),
-			   (unsigned long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= OP_MASK_SHAMT;
-		}
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_SHAMT;
+		as_warn (_("Improper shift amount (%lu)"),
+			 (unsigned long) imm_expr.X_add_number);
+	      INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8229,7 +8216,7 @@ do_msbd:
 	      if ((unsigned long) imm_expr.X_add_number < 32
 		  || (unsigned long) imm_expr.X_add_number > 63)
 		break;
-	      ip->insn_opcode |= (imm_expr.X_add_number - 32) << OP_SH_SHAMT;
+	      INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number - 32);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8239,16 +8226,13 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > 31)
-		{
-		  as_warn (_("Invalid value for `%s' (%lu)"),
-			   ip->insn_mo->name,
-			   (unsigned long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= 0x1f;
-		}
+		as_warn (_("Invalid value for `%s' (%lu)"),
+			 ip->insn_mo->name,
+			 (unsigned long) imm_expr.X_add_number);
 	      if (*args == 'k')
-		ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CACHE;
+		INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
 	      else
-		ip->insn_opcode |= imm_expr.X_add_number << OP_SH_PREFX;
+		INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8257,12 +8241,9 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > 1023)
-		{
-		  as_warn (_("Illegal break code (%lu)"),
-			   (unsigned long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= OP_MASK_CODE;
-		}
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE;
+		as_warn (_("Illegal break code (%lu)"),
+			 (unsigned long) imm_expr.X_add_number);
+	      INSERT_OPERAND (CODE, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8271,12 +8252,9 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > 1023)
-		{
-		  as_warn (_("Illegal lower break code (%lu)"),
-			   (unsigned long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= OP_MASK_CODE2;
-		}
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE2;
+		as_warn (_("Illegal lower break code (%lu)"),
+			 (unsigned long) imm_expr.X_add_number);
+	      INSERT_OPERAND (CODE2, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8287,7 +8265,7 @@ do_msbd:
 	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
 		as_warn (_("Illegal 20-bit code (%lu)"),
 			 (unsigned long) imm_expr.X_add_number);
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE20;
+	      INSERT_OPERAND (CODE20, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8312,7 +8290,7 @@ do_msbd:
 	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
 		as_warn (_("Illegal 19-bit code (%lu)"),
 			 (unsigned long) imm_expr.X_add_number);
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_CODE19;
+	      INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8321,12 +8299,9 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      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);
-		  imm_expr.X_add_number &= OP_MASK_PERFREG;
-		}
-	      ip->insn_opcode |= (imm_expr.X_add_number << OP_SH_PERFREG);
+		as_warn (_("Invalid performance register (%lu)"),
+			 (unsigned long) imm_expr.X_add_number);
+	      INSERT_OPERAND (PERFREG, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8463,21 +8438,21 @@ do_msbd:
 		    case 's':
 		    case 'v':
 		    case 'b':
-		      ip->insn_opcode |= regno << OP_SH_RS;
+		      INSERT_OPERAND (RS, *ip, regno);
 		      break;
 		    case 'd':
 		    case 'G':
 		    case 'K':
-		      ip->insn_opcode |= regno << OP_SH_RD;
+		      INSERT_OPERAND (RD, *ip, regno);
 		      break;
 		    case 'U':
-		      ip->insn_opcode |= regno << OP_SH_RD;
-		      ip->insn_opcode |= regno << OP_SH_RT;
+		      INSERT_OPERAND (RD, *ip, regno);
+		      INSERT_OPERAND (RT, *ip, regno);
 		      break;
 		    case 'w':
 		    case 't':
 		    case 'E':
-		      ip->insn_opcode |= regno << OP_SH_RT;
+		      INSERT_OPERAND (RT, *ip, regno);
 		      break;
 		    case 'x':
 		      /* This case exists because on the r3000 trunc
@@ -8508,10 +8483,10 @@ do_msbd:
 		{
 		case 'r':
 		case 'v':
-		  ip->insn_opcode |= lastregno << OP_SH_RS;
+		  INSERT_OPERAND (RS, *ip, lastregno);
 		  continue;
 		case 'w':
-		  ip->insn_opcode |= lastregno << OP_SH_RT;
+		  INSERT_OPERAND (RT, *ip, lastregno);
 		  continue;
 		}
 	      break;
@@ -8520,12 +8495,9 @@ do_msbd:
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
-		{
-		  as_warn ("Improper align amount (%ld), using low bits",
-			   (long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= OP_MASK_ALN;
-		}
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_ALN;
+		as_warn ("Improper align amount (%ld), using low bits",
+			 (long) imm_expr.X_add_number);
+	      INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -8537,17 +8509,13 @@ do_msbd:
 		  my_getExpression (&imm_expr, s);
 		  check_absolute_expr (ip, &imm_expr);
 		  if ((unsigned long) imm_expr.X_add_number > OP_MASK_FT)
-		    {
-		      as_warn (_("Invalid MDMX Immediate (%ld)"),
-			       (long) imm_expr.X_add_number);
-		      imm_expr.X_add_number &= OP_MASK_FT;
-		    }
-		  imm_expr.X_add_number &= OP_MASK_FT;
+		    as_warn (_("Invalid MDMX Immediate (%ld)"),
+			     (long) imm_expr.X_add_number);
+		  INSERT_OPERAND (FT, *ip, imm_expr.X_add_number);
 		  if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
 		    ip->insn_opcode |= MDMX_FMTSEL_IMM_QH << OP_SH_VSEL;
 		  else
 		    ip->insn_opcode |= MDMX_FMTSEL_IMM_OB << OP_SH_VSEL;
-		  ip->insn_opcode |= imm_expr.X_add_number << OP_SH_FT;
 		  imm_expr.X_op = O_absent;
 		  s = expr_end;
 		  continue;
@@ -8610,12 +8578,12 @@ do_msbd:
 		    {
 		    case 'D':
 		    case 'X':
-		      ip->insn_opcode |= regno << OP_SH_FD;
+		      INSERT_OPERAND (FD, *ip, regno);
 		      break;
 		    case 'V':
 		    case 'S':
 		    case 'Y':
-		      ip->insn_opcode |= regno << OP_SH_FS;
+		      INSERT_OPERAND (FS, *ip, regno);
 		      break;
 		    case 'Q':
 		      /* This is like 'Z', but also needs to fix the MDMX
@@ -8655,10 +8623,10 @@ do_msbd:
 		    case 'W':
 		    case 'T':
 		    case 'Z':
-		      ip->insn_opcode |= regno << OP_SH_FT;
+		      INSERT_OPERAND (FT, *ip, regno);
 		      break;
 		    case 'R':
-		      ip->insn_opcode |= regno << OP_SH_FR;
+		      INSERT_OPERAND (FR, *ip, regno);
 		      break;
 		    }
 		  lastregno = regno;
@@ -8668,10 +8636,10 @@ do_msbd:
 	      switch (*args++)
 		{
 		case 'V':
-		  ip->insn_opcode |= lastregno << OP_SH_FS;
+		  INSERT_OPERAND (FS, *ip, lastregno);
 		  continue;
 		case 'W':
-		  ip->insn_opcode |= lastregno << OP_SH_FT;
+		  INSERT_OPERAND (FT, *ip, lastregno);
 		  continue;
 		}
 	      break;
@@ -9001,9 +8969,9 @@ do_msbd:
 		as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
 			str, regno);
 	      if (*args == 'N')
-		ip->insn_opcode |= regno << OP_SH_BCC;
+		INSERT_OPERAND (BCC, *ip, regno);
 	      else
-		ip->insn_opcode |= regno << OP_SH_CCC;
+		INSERT_OPERAND (CCC, *ip, regno);
 	      continue;
 
 	    case 'H':
@@ -9041,7 +9009,7 @@ do_msbd:
 		  imm_expr.X_add_number = 0;
 		}
 
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECBYTE;
+	      INSERT_OPERAND (VECBYTE, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -9058,7 +9026,7 @@ do_msbd:
 		  imm_expr.X_add_number = 0;
 		}
 
-	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECALIGN;
+	      INSERT_OPERAND (VECALIGN, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;
@@ -9234,10 +9202,10 @@ mips16_ip (char *str, struct mips_cl_ins
 	      switch (*++args)
 		{
 		case 'v':
-		  ip->insn_opcode |= lastregno << MIPS16OP_SH_RX;
+		  MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
 		  continue;
 		case 'w':
-		  ip->insn_opcode |= lastregno << MIPS16OP_SH_RY;
+		  MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
 		  continue;
 		}
 	      break;
@@ -9253,9 +9221,9 @@ mips16_ip (char *str, struct mips_cl_ins
 	      if (s[0] != '$')
 		{
 		  if (c == 'v')
-		    ip->insn_opcode |= lastregno << MIPS16OP_SH_RX;
+		    MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
 		  else
-		    ip->insn_opcode |= lastregno << MIPS16OP_SH_RY;
+		    MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
 		  ++args;
 		  continue;
 		}
@@ -9390,27 +9358,27 @@ mips16_ip (char *str, struct mips_cl_ins
 		{
 		case 'x':
 		case 'v':
-		  ip->insn_opcode |= regno << MIPS16OP_SH_RX;
+		  MIPS16_INSERT_OPERAND (RX, *ip, regno);
 		  break;
 		case 'y':
 		case 'w':
-		  ip->insn_opcode |= regno << MIPS16OP_SH_RY;
+		  MIPS16_INSERT_OPERAND (RY, *ip, regno);
 		  break;
 		case 'z':
-		  ip->insn_opcode |= regno << MIPS16OP_SH_RZ;
+		  MIPS16_INSERT_OPERAND (RZ, *ip, regno);
 		  break;
 		case 'Z':
-		  ip->insn_opcode |= regno << MIPS16OP_SH_MOVE32Z;
+		  MIPS16_INSERT_OPERAND (MOVE32Z, *ip, regno);
 		case '0':
 		case 'S':
 		case 'R':
 		  break;
 		case 'X':
-		  ip->insn_opcode |= regno << MIPS16OP_SH_REGR32;
+		  MIPS16_INSERT_OPERAND (REGR32, *ip, regno);
 		  break;
 		case 'Y':
 		  regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
-		  ip->insn_opcode |= regno << MIPS16OP_SH_REG32R;
+		  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
 		  break;
 		default:
 		  internalError ();
@@ -9512,13 +9480,10 @@ mips16_ip (char *str, struct mips_cl_ins
 	      my_getExpression (&imm_expr, s);
 	      check_absolute_expr (ip, &imm_expr);
 	      if ((unsigned long) imm_expr.X_add_number > 63)
-		{
-		  as_warn (_("Invalid value for `%s' (%lu)"),
-			   ip->insn_mo->name,
-			   (unsigned long) imm_expr.X_add_number);
-		  imm_expr.X_add_number &= 0x3f;
-		}
-	      ip->insn_opcode |= imm_expr.X_add_number << MIPS16OP_SH_IMM6;
+		as_warn (_("Invalid value for `%s' (%lu)"),
+			 ip->insn_mo->name,
+			 (unsigned long) imm_expr.X_add_number);
+	      MIPS16_INSERT_OPERAND (IMM6, *ip, imm_expr.X_add_number);
 	      imm_expr.X_op = O_absent;
 	      s = expr_end;
 	      continue;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11]
  2005-03-08 14:50     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Richard Sandiford
@ 2005-03-08 14:56       ` Richard Sandiford
  2005-03-08 15:00         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Richard Sandiford
  2005-03-08 19:12         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Eric Christopher
  2005-03-08 19:09       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 14:56 UTC (permalink / raw)
  To: binutils

This patch introduces a new set of functions for handling mips_cl_insns
and for manipulating the history buffer:

   - create_insn
        Initialise a mips_cl_insn from an opcode entry

   - install_insn
        Install a mips_cl_insn's opcode at the position specified
        by its frag and where fields.

   - move_insn
        Change the position of a mips_cl_insn.

   - add_fixed_insn
        Install a mips_cl_insn at the end of the current frag.

   - add_relaxed_insn
        Start a variant frag and install a mips_cl_insn at the
        start of the variant part.

   - insert_into_history
        Insert copies of a mips_cl_insn into the history buffer.

   - emit_nop
        Add a nop to the end of the current frag and record it
        in the history buffer.

Most of this is just cleanup, but the new behaviour of emit_nop() is
important.  It means that append_insn() now adds nops to the history
buffer at the same time as emitting the nops, not when emitting the
instruction _after_ the nops.  This simplified some later changes.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.c (dummy_opcode): Delete.
	(nop_insn, mips16_nop_insn): New variables.
	(NOP_INSN): New macro.
	(insn_length, create_insn, install_insn, move_insn, add_fixed_insn)
	(add_relaxed_insn, insert_into_history, emit_nop): New functions.
	(md_begin): Initialize nop_insn and mips16_nop_insn.
	(append_insn): Use the new emit_nop function to add nops, recording
	them in the history buffer.  Use add_fixed_insn or add_relaxed_insn
	to reserve room for the instruction and install_insn to install the
	final form.  Use insert_into_history to record the instruction in
	the history buffer.  Use move_insn to do delay slot filling.
	(mips_emit_delays): Use add_fixed_insn instead of the emit_nop macro.
	(macro_build, mips16_macro_build, macro_build_lui, mips_ip)
	(mips16_ip): Use create_insn to initialize mips_cl_insns.

diff -crpN gas.5/config/tc-mips.c gas/config/tc-mips.c
*** gas.5/config/tc-mips.c	2005-03-08 10:19:44.469831745 +0000
--- gas/config/tc-mips.c	2005-03-08 10:30:43.161925269 +0000
*************** static int mips_debug = 0;
*** 560,568 ****
  /* A list of previous instructions, with index 0 being the most recent.  */
  static struct mips_cl_insn history[2];
  
! /* If we don't want information for a history[] entry, we
!    point the insn_mo field at this dummy integer.  */
! static const struct mips_opcode dummy_opcode = { NULL, NULL, 0, 0, 0, 0, 0 };
  
  /* If this is set, it points to a frag holding nop instructions which
     were inserted before the start of a noreorder section.  If those
--- 560,570 ----
  /* A list of previous instructions, with index 0 being the most recent.  */
  static struct mips_cl_insn history[2];
  
! /* Nop instructions used by emit_nop.  */
! static struct mips_cl_insn nop_insn, mips16_nop_insn;
! 
! /* 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
*************** mips_target_format (void)
*** 1159,1164 ****
--- 1161,1290 ----
      }
  }
  
+ /* 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);
+ }
+ 
  /* 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.  */
  
*************** md_begin (void)
*** 1192,1197 ****
--- 1318,1328 ----
  	    {
  	      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;
  	}
*************** md_begin (void)
*** 1219,1224 ****
--- 1350,1360 ----
  		       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
*************** append_insn (struct mips_cl_insn *ip, ex
*** 1646,1657 ****
  	     bfd_reloc_code_real_type *reloc_type)
  {
    register unsigned long prev_pinfo, pinfo;
-   char *f;
-   fixS *fixp[3];
    int nops = 0;
    relax_stateT prev_insn_frag_type = 0;
    bfd_boolean relaxed_branch = FALSE;
-   bfd_boolean force_new_frag = FALSE;
  
    /* Mark instruction labels in mips16 mode.  */
    mips16_mark_labels ();
--- 1782,1790 ----
*************** append_insn (struct mips_cl_insn *ip, ex
*** 1684,1695 ****
  	 benefit hand written assembly code, and does not seem worth
  	 it.  */
  
-       /* This is how a NOP is emitted.  */
- #define emit_nop()					\
-   (mips_opts.mips16					\
-    ? md_number_to_chars (frag_more (2), 0x6500, 2)	\
-    : md_number_to_chars (frag_more (4), 0, 4))
- 
        /* The previous insn might require a delay slot, depending upon
  	 the contents of the current insn.  */
        if (! mips_opts.mips16
--- 1817,1822 ----
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2061,2092 ****
        && !mips_opts.mips16)
      {
        relaxed_branch = TRUE;
!       f = frag_var (rs_machine_dependent,
! 		    relaxed_branch_length
! 		    (NULL, NULL,
! 		     (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
! 		     : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 : 0), 4,
! 		    RELAX_BRANCH_ENCODE
! 		    (pinfo & INSN_UNCOND_BRANCH_DELAY,
! 		     pinfo & INSN_COND_BRANCH_LIKELY,
! 		     pinfo & INSN_WRITE_GPR_31,
! 		     0),
! 		    address_expr->X_add_symbol,
! 		    address_expr->X_add_number,
! 		    0);
        *reloc_type = BFD_RELOC_UNUSED;
      }
    else if (*reloc_type > BFD_RELOC_UNUSED)
      {
        /* We need to set up a variant frag.  */
        assert (mips_opts.mips16 && address_expr != NULL);
!       f = frag_var (rs_machine_dependent, 4, 0,
! 		    RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED,
! 					 mips16_small, mips16_ext,
! 					 (prev_pinfo
! 					  & INSN_UNCOND_BRANCH_DELAY),
! 					 history[0].mips16_absolute_jump_p),
! 		    make_expr_symbol (address_expr), 0, NULL);
      }
    else if (mips_opts.mips16
  	   && ! ip->use_extend
--- 2188,2218 ----
        && !mips_opts.mips16)
      {
        relaxed_branch = TRUE;
!       add_relaxed_insn (ip, (relaxed_branch_length
! 			     (NULL, NULL,
! 			      (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
! 			      : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
! 			      : 0)), 4,
! 			RELAX_BRANCH_ENCODE
! 			(pinfo & INSN_UNCOND_BRANCH_DELAY,
! 			 pinfo & INSN_COND_BRANCH_LIKELY,
! 			 pinfo & INSN_WRITE_GPR_31,
! 			 0),
! 			address_expr->X_add_symbol,
! 			address_expr->X_add_number);
        *reloc_type = BFD_RELOC_UNUSED;
      }
    else if (*reloc_type > BFD_RELOC_UNUSED)
      {
        /* We need to set up a variant frag.  */
        assert (mips_opts.mips16 && address_expr != NULL);
!       add_relaxed_insn (ip, 4, 0,
! 			RELAX_MIPS16_ENCODE
! 			(*reloc_type - BFD_RELOC_UNUSED,
! 			 mips16_small, mips16_ext,
! 			 prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
! 			 history[0].mips16_absolute_jump_p),
! 			make_expr_symbol (address_expr), 0);
      }
    else if (mips_opts.mips16
  	   && ! ip->use_extend
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2095,2101 ****
        /* Make sure there is enough room to swap this instruction with
           a following jump instruction.  */
        frag_grow (6);
!       f = frag_more (2);
      }
    else
      {
--- 2221,2227 ----
        /* Make sure there is enough room to swap this instruction with
           a following jump instruction.  */
        frag_grow (6);
!       add_fixed_insn (ip);
      }
    else
      {
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2119,2128 ****
        if (mips_relax.sequence != 1)
  	mips_macro_warning.sizes[1] += 4;
  
!       f = frag_more (4);
      }
  
-   fixp[0] = fixp[1] = fixp[2] = NULL;
    if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
      {
        if (address_expr->X_op == O_constant)
--- 2245,2258 ----
        if (mips_relax.sequence != 1)
  	mips_macro_warning.sizes[1] += 4;
  
!       if (mips_opts.mips16)
! 	{
! 	  ip->fixed_p = 1;
! 	  ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
! 	}
!       add_fixed_insn (ip);
      }
  
    if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
      {
        if (address_expr->X_op == O_constant)
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2203,2213 ****
  	      break;
  
  	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
! 	  fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal,
! 				 bfd_get_reloc_size(howto),
! 				 address_expr,
! 				 reloc_type[0] == BFD_RELOC_16_PCREL_S2,
! 				 reloc_type[0]);
  
  	  /* These relocations can have an addend that won't fit in
  	     4 octets for 64bit assembly.  */
--- 2333,2343 ----
  	      break;
  
  	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
! 	  ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
! 				     bfd_get_reloc_size (howto),
! 				     address_expr,
! 				     reloc_type[0] == BFD_RELOC_16_PCREL_S2,
! 				     reloc_type[0]);
  
  	  /* These relocations can have an addend that won't fit in
  	     4 octets for 64bit assembly.  */
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2232,2243 ****
  		  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
  		  || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
  		  || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
! 	    fixp[0]->fx_no_overflow = 1;
  
  	  if (mips_relax.sequence)
  	    {
  	      if (mips_relax.first_fixup == 0)
! 		mips_relax.first_fixup = fixp[0];
  	    }
  	  else if (reloc_needs_lo_p (*reloc_type))
  	    {
--- 2362,2373 ----
  		  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
  		  || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
  		  || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
! 	    ip->fixp[0]->fx_no_overflow = 1;
  
  	  if (mips_relax.sequence)
  	    {
  	      if (mips_relax.first_fixup == 0)
! 		mips_relax.first_fixup = ip->fixp[0];
  	    }
  	  else if (reloc_needs_lo_p (*reloc_type))
  	    {
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2253,2259 ****
  		  hi_fixup->next = mips_hi_fixup_list;
  		  mips_hi_fixup_list = hi_fixup;
  		}
! 	      hi_fixup->fixp = fixp[0];
  	      hi_fixup->seg = now_seg;
  	    }
  
--- 2383,2389 ----
  		  hi_fixup->next = mips_hi_fixup_list;
  		  mips_hi_fixup_list = hi_fixup;
  		}
! 	      hi_fixup->fixp = ip->fixp[0];
  	      hi_fixup->seg = now_seg;
  	    }
  
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2265,2297 ****
  	  for (i = 1; i < 3; i++)
  	    if (reloc_type[i] != BFD_RELOC_UNUSED)
  	      {
! 		fixp[i] = fix_new (frag_now, fixp[0]->fx_where,
! 				   fixp[0]->fx_size, NULL, 0,
! 				   FALSE, reloc_type[i]);
  
  		/* Use fx_tcbit to mark compound relocs.  */
! 		fixp[0]->fx_tcbit = 1;
! 		fixp[i]->fx_tcbit = 1;
  	      }
  	}
      }
! 
!   if (! mips_opts.mips16)
!     md_number_to_chars (f, ip->insn_opcode, 4);
!   else if (*reloc_type == BFD_RELOC_MIPS16_JMP)
!     {
!       md_number_to_chars (f, ip->insn_opcode >> 16, 2);
!       md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2);
!     }
!   else
!     {
!       if (ip->use_extend)
! 	{
! 	  md_number_to_chars (f, 0xf000 | ip->extend, 2);
! 	  f += 2;
! 	}
!       md_number_to_chars (f, ip->insn_opcode, 2);
!     }
  
    /* Update the register mask information.  */
    if (! mips_opts.mips16)
--- 2395,2411 ----
  	  for (i = 1; i < 3; i++)
  	    if (reloc_type[i] != BFD_RELOC_UNUSED)
  	      {
! 		ip->fixp[i] = fix_new (ip->frag, ip->where,
! 				       ip->fixp[0]->fx_size, NULL, 0,
! 				       FALSE, reloc_type[i]);
  
  		/* Use fx_tcbit to mark compound relocs.  */
! 		ip->fixp[0]->fx_tcbit = 1;
! 		ip->fixp[i]->fx_tcbit = 1;
  	      }
  	}
      }
!   install_insn (ip);
  
    /* Update the register mask information.  */
    if (! mips_opts.mips16)
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2534,2696 ****
  		 portions of this object file; we could pick up the
  		 instruction at the destination, put it in the delay
  		 slot, and bump the destination address.  */
  	      emit_nop ();
  	      if (mips_relax.sequence)
  		mips_relax.sizes[mips_relax.sequence - 1] += 4;
- 	      /* Update the previous insn information.  */
- 	      history[1].insn_mo = ip->insn_mo;
- 	      history[1].use_extend = ip->use_extend;
- 	      history[1].extend = ip->extend;
- 	      history[1].insn_opcode = ip->insn_opcode;
- 	      history[0].insn_mo = &dummy_opcode;
  	    }
  	  else
  	    {
  	      /* It looks like we can actually do the swap.  */
! 	      if (! mips_opts.mips16)
  		{
! 		  char *prev_f;
! 		  char temp[4];
! 
! 		  prev_f = history[0].frag->fr_literal + history[0].where;
! 		  if (!relaxed_branch)
! 		    {
! 		      /* If this is not a relaxed branch, then just
! 			 swap the instructions.  */
! 		      memcpy (temp, prev_f, 4);
! 		      memcpy (prev_f, f, 4);
! 		      memcpy (f, temp, 4);
! 		    }
! 		  else
! 		    {
! 		      /* If this is a relaxed branch, then we move the
! 			 instruction to be placed in the delay slot to
! 			 the current frag, shrinking the fixed part of
! 			 the originating frag.  If the branch occupies
! 			 the tail of the latter, we move it backwards,
! 			 into the space freed by the moved instruction.  */
! 		      f = frag_more (4);
! 		      memcpy (f, prev_f, 4);
! 		      history[0].frag->fr_fix -= 4;
! 		      if (history[0].frag->fr_type == rs_machine_dependent)
! 			memmove (prev_f, prev_f + 4, history[0].frag->fr_var);
! 		    }
! 
! 		  if (history[0].fixp[0])
! 		    {
! 		      history[0].fixp[0]->fx_frag = frag_now;
! 		      history[0].fixp[0]->fx_where = f - frag_now->fr_literal;
! 		    }
! 		  if (history[0].fixp[1])
! 		    {
! 		      history[0].fixp[1]->fx_frag = frag_now;
! 		      history[0].fixp[1]->fx_where = f - frag_now->fr_literal;
! 		    }
! 		  if (history[0].fixp[2])
! 		    {
! 		      history[0].fixp[2]->fx_frag = frag_now;
! 		      history[0].fixp[2]->fx_where = f - frag_now->fr_literal;
! 		    }
! 		  if (history[0].fixp[0] && HAVE_NEWABI
! 		      && history[0].frag != frag_now
! 		      && (history[0].fixp[0]->fx_r_type
! 			  == BFD_RELOC_MIPS_GOT_DISP
! 			  || (history[0].fixp[0]->fx_r_type
! 			      == BFD_RELOC_MIPS_CALL16)))
! 		    {
! 		      /* To avoid confusion in tc_gen_reloc, we must
! 			 ensure that this does not become a variant
! 			 frag.  */
! 		      force_new_frag = TRUE;
! 		    }
! 
! 		  if (!relaxed_branch)
! 		    {
! 		      if (fixp[0])
! 			{
! 			  fixp[0]->fx_frag = history[0].frag;
! 			  fixp[0]->fx_where = history[0].where;
! 			}
! 		      if (fixp[1])
! 			{
! 			  fixp[1]->fx_frag = history[0].frag;
! 			  fixp[1]->fx_where = history[0].where;
! 			}
! 		      if (fixp[2])
! 			{
! 			  fixp[2]->fx_frag = history[0].frag;
! 			  fixp[2]->fx_where = history[0].where;
! 			}
! 		    }
! 		  else if (history[0].frag->fr_type == rs_machine_dependent)
! 		    {
! 		      if (fixp[0])
! 			fixp[0]->fx_where -= 4;
! 		      if (fixp[1])
! 			fixp[1]->fx_where -= 4;
! 		      if (fixp[2])
! 			fixp[2]->fx_where -= 4;
! 		    }
  		}
  	      else
  		{
! 		  char *prev_f;
! 		  char temp[2];
! 
! 		  assert (history[0].fixp[0] == NULL);
! 		  assert (history[0].fixp[1] == NULL);
! 		  assert (history[0].fixp[2] == NULL);
! 		  prev_f = history[0].frag->fr_literal + history[0].where;
! 		  memcpy (temp, prev_f, 2);
! 		  memcpy (prev_f, f, 2);
! 		  if (*reloc_type != BFD_RELOC_MIPS16_JMP)
! 		    {
! 		      assert (*reloc_type == BFD_RELOC_UNUSED);
! 		      memcpy (f, temp, 2);
! 		    }
! 		  else
! 		    {
! 		      memcpy (f, f + 2, 2);
! 		      memcpy (f + 2, temp, 2);
! 		    }
! 		  if (fixp[0])
! 		    {
! 		      fixp[0]->fx_frag = history[0].frag;
! 		      fixp[0]->fx_where = history[0].where;
! 		    }
! 		  if (fixp[1])
! 		    {
! 		      fixp[1]->fx_frag = history[0].frag;
! 		      fixp[1]->fx_where = history[0].where;
! 		    }
! 		  if (fixp[2])
! 		    {
! 		      fixp[2]->fx_frag = history[0].frag;
! 		      fixp[2]->fx_where = history[0].where;
! 		    }
  		}
! 
! 	      /* Update the previous insn information; leave history[0]
! 		 unchanged.  */
! 	      history[1].insn_mo = ip->insn_mo;
! 	      history[1].use_extend = ip->use_extend;
! 	      history[1].extend = ip->extend;
! 	      history[1].insn_opcode = ip->insn_opcode;
  	    }
- 	  history[0].fixed_p = 1;
  
  	  /* If that was an unconditional branch, forget the previous
  	     insn information.  */
  	  if (pinfo & INSN_UNCOND_BRANCH_DELAY)
! 	    {
! 	      history[1].insn_mo = &dummy_opcode;
! 	      history[0].insn_mo = &dummy_opcode;
! 	    }
! 
! 	  history[0].fixp[0] = NULL;
! 	  history[0].fixp[1] = NULL;
! 	  history[0].fixp[2] = NULL;
! 	  history[0].mips16_absolute_jump_p = 0;
  	}
        else if (pinfo & INSN_COND_BRANCH_LIKELY)
  	{
--- 2648,2693 ----
  		 portions of this object file; we could pick up the
  		 instruction at the destination, put it in the delay
  		 slot, and bump the destination address.  */
+ 	      insert_into_history (0, 1, ip);
  	      emit_nop ();
  	      if (mips_relax.sequence)
  		mips_relax.sizes[mips_relax.sequence - 1] += 4;
  	    }
  	  else
  	    {
  	      /* It looks like we can actually do the swap.  */
! 	      struct mips_cl_insn delay = history[0];
! 	      if (mips_opts.mips16)
  		{
! 		  know (delay.frag == ip->frag);
! 		  move_insn (ip, delay.frag, delay.where);
! 		  move_insn (&delay, ip->frag, ip->where + insn_length (ip));
! 		}
! 	      else if (relaxed_branch)
! 		{
! 		  /* Add the delay slot instruction to the end of the
! 		     current frag and shrink the fixed part of the
! 		     original frag.  If the branch occupies the tail of
! 		     the latter, move it backwards to cover the gap.  */
! 		  delay.frag->fr_fix -= 4;
! 		  if (delay.frag == ip->frag)
! 		    move_insn (ip, ip->frag, ip->where - 4);
! 		  add_fixed_insn (&delay);
  		}
  	      else
  		{
! 		  move_insn (&delay, ip->frag, ip->where);
! 		  move_insn (ip, history[0].frag, history[0].where);
  		}
! 	      history[0] = *ip;
! 	      delay.fixed_p = 1;
! 	      insert_into_history (0, 1, &delay);
  	    }
  
  	  /* If that was an unconditional branch, forget the previous
  	     insn information.  */
  	  if (pinfo & INSN_UNCOND_BRANCH_DELAY)
! 	    mips_no_prev_insn (FALSE);
  	}
        else if (pinfo & INSN_COND_BRANCH_LIKELY)
  	{
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2698,2766 ****
  	     is look at the target, copy the instruction found there
  	     into the delay slot, and increment the branch to jump to
  	     the next instruction.  */
  	  emit_nop ();
- 	  /* Update the previous insn information.  */
- 	  history[1].insn_mo = ip->insn_mo;
- 	  history[1].use_extend = ip->use_extend;
- 	  history[1].extend = ip->extend;
- 	  history[1].insn_opcode = ip->insn_opcode;
- 	  history[0].insn_mo = &dummy_opcode;
- 	  history[0].fixp[0] = NULL;
- 	  history[0].fixp[1] = NULL;
- 	  history[0].fixp[2] = NULL;
- 	  history[0].mips16_absolute_jump_p = 0;
- 	  history[0].fixed_p = 1;
  	}
        else
! 	{
! 	  /* Update the previous insn information.  */
! 	  if (nops > 0)
! 	    history[1].insn_mo = &dummy_opcode;
! 	  else
! 	    {
! 	      history[1].insn_mo = history[0].insn_mo;
! 	      history[1].use_extend = history[0].use_extend;
! 	      history[1].extend = history[0].extend;
! 	      history[1].insn_opcode = history[0].insn_opcode;
! 	    }
! 	  history[0].insn_mo = ip->insn_mo;
! 	  history[0].use_extend = ip->use_extend;
! 	  history[0].extend = ip->extend;
! 	  history[0].insn_opcode = ip->insn_opcode;
! 	  history[0].fixed_p = (mips_opts.mips16
! 				&& (ip->use_extend
! 				    || *reloc_type > BFD_RELOC_UNUSED));
! 	  history[0].fixp[0] = fixp[0];
! 	  history[0].fixp[1] = fixp[1];
! 	  history[0].fixp[2] = fixp[2];
! 	  history[0].mips16_absolute_jump_p = (reloc_type[0]
! 					       == BFD_RELOC_MIPS16_JMP);
! 	}
! 
!       history[1].noreorder_p = history[0].noreorder_p;
!       history[0].noreorder_p = 0;
!       history[0].frag = frag_now;
!       history[0].where = f - frag_now->fr_literal;
!     }
!   else if (mips_relax.sequence != 2)
!     {
!       /* We need to record a bit of information even when we are not
!          reordering, in order to determine the base address for mips16
!          PC relative relocs.  */
!       history[1].insn_mo = history[0].insn_mo;
!       history[1].use_extend = history[0].use_extend;
!       history[1].extend = history[0].extend;
!       history[1].insn_opcode = history[0].insn_opcode;
!       history[0].insn_mo = ip->insn_mo;
!       history[0].use_extend = ip->use_extend;
!       history[0].extend = ip->extend;
!       history[0].insn_opcode = ip->insn_opcode;
!       history[0].mips16_absolute_jump_p = (reloc_type[0]
! 					   == BFD_RELOC_MIPS16_JMP);
!       history[1].noreorder_p = history[0].noreorder_p;
!       history[0].noreorder_p = 1;
!       history[0].fixed_p = 1;
      }
  
    /* We just output an insn, so the next one doesn't have a label.  */
    mips_clear_insn_labels ();
--- 2695,2708 ----
  	     is look at the target, copy the instruction found there
  	     into the delay slot, and increment the branch to jump to
  	     the next instruction.  */
+ 	  insert_into_history (0, 1, ip);
  	  emit_nop ();
  	}
        else
! 	insert_into_history (0, 1, ip);
      }
+   else
+     insert_into_history (0, 1, ip);
  
    /* We just output an insn, so the next one doesn't have a label.  */
    mips_clear_insn_labels ();
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2773,2791 ****
  static void
  mips_no_prev_insn (int preserve)
  {
    if (! preserve)
      {
-       history[0].insn_mo = &dummy_opcode;
-       history[1].insn_mo = &dummy_opcode;
        prev_nop_frag = NULL;
        prev_nop_frag_holds = 0;
        prev_nop_frag_required = 0;
        prev_nop_frag_since = 0;
      }
!   history[0].fixed_p = 1;
!   history[0].noreorder_p = 0;
!   history[0].mips16_absolute_jump_p = 0;
!   history[1].noreorder_p = 0;
    mips_clear_insn_labels ();
  }
  
--- 2715,2738 ----
  static void
  mips_no_prev_insn (int preserve)
  {
+   size_t i;
+  
    if (! preserve)
      {
        prev_nop_frag = NULL;
        prev_nop_frag_holds = 0;
        prev_nop_frag_required = 0;
        prev_nop_frag_since = 0;
+       for (i = 0; i < ARRAY_SIZE (history); i++)
+ 	history[i] = (mips_opts.mips16 ? mips16_nop_insn : nop_insn);
      }
!   else
!     for (i = 0; i < ARRAY_SIZE (history); i++)
!       {
! 	history[i].fixed_p = 1;
! 	history[i].noreorder_p = 0;
! 	history[i].mips16_absolute_jump_p = 0;
!       }
    mips_clear_insn_labels ();
  }
  
*************** mips_emit_delays (bfd_boolean insns)
*** 2874,2880 ****
  	    }
  
  	  for (; nops > 0; --nops)
! 	    emit_nop ();
  
  	  if (insns)
  	    {
--- 2821,2827 ----
  	    }
  
  	  for (; nops > 0; --nops)
! 	    add_fixed_insn (NOP_INSN);
  
  	  if (insns)
  	    {
*************** macro_read_relocs (va_list *args, bfd_re
*** 2997,3002 ****
--- 2944,2950 ----
  static void
  macro_build (expressionS *ep, const char *name, const char *fmt, ...)
  {
+   const struct mips_opcode *mo;
    struct mips_cl_insn insn;
    bfd_reloc_code_real_type r[3];
    va_list args;
*************** macro_build (expressionS *ep, const char
*** 3013,3042 ****
    r[0] = BFD_RELOC_UNUSED;
    r[1] = BFD_RELOC_UNUSED;
    r[2] = BFD_RELOC_UNUSED;
!   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
!   assert (insn.insn_mo);
!   assert (strcmp (name, insn.insn_mo->name) == 0);
! 
!   /* Search until we get a match for NAME.  */
!   while (1)
!     {
!       /* It is assumed here that macros will never generate
!          MDMX or MIPS-3D instructions.  */
!       if (strcmp (fmt, insn.insn_mo->args) == 0
! 	  && insn.insn_mo->pinfo != INSN_MACRO
!   	  && OPCODE_IS_MEMBER (insn.insn_mo,
!   			       (mips_opts.isa
! 	      		        | (file_ase_mips16 ? INSN_MIPS16 : 0)),
  			       mips_opts.arch)
! 	  && (mips_opts.arch != CPU_R4650 || (insn.insn_mo->pinfo & FP_D) == 0))
! 	break;
! 
!       ++insn.insn_mo;
!       assert (insn.insn_mo->name);
!       assert (strcmp (name, insn.insn_mo->name) == 0);
      }
  
!   insn.insn_opcode = insn.insn_mo->match;
    for (;;)
      {
        switch (*fmt++)
--- 2961,2986 ----
    r[0] = BFD_RELOC_UNUSED;
    r[1] = BFD_RELOC_UNUSED;
    r[2] = BFD_RELOC_UNUSED;
!   mo = (struct mips_opcode *) hash_find (op_hash, name);
!   assert (mo);
!   assert (strcmp (name, mo->name) == 0);
! 
!   /* Search until we get a match for NAME.  It is assumed here that
!      macros will never generate MDMX or MIPS-3D instructions.  */
!   while (strcmp (fmt, mo->args) != 0
! 	 || mo->pinfo == INSN_MACRO
! 	 || !OPCODE_IS_MEMBER (mo,
! 			       (mips_opts.isa
! 				| (file_ase_mips16 ? INSN_MIPS16 : 0)),
  			       mips_opts.arch)
! 	 || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0))
!     {
!       ++mo;
!       assert (mo->name);
!       assert (strcmp (name, mo->name) == 0);
      }
  
!   create_insn (&insn, mo);
    for (;;)
      {
        switch (*fmt++)
*************** static void
*** 3219,3243 ****
  mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
  		    va_list args)
  {
    struct mips_cl_insn insn;
    bfd_reloc_code_real_type r[3]
      = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
  
!   insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
!   assert (insn.insn_mo);
!   assert (strcmp (name, insn.insn_mo->name) == 0);
! 
!   while (strcmp (fmt, insn.insn_mo->args) != 0
! 	 || insn.insn_mo->pinfo == INSN_MACRO)
!     {
!       ++insn.insn_mo;
!       assert (insn.insn_mo->name);
!       assert (strcmp (name, insn.insn_mo->name) == 0);
!     }
  
!   insn.insn_opcode = insn.insn_mo->match;
!   insn.use_extend = FALSE;
  
    for (;;)
      {
        int c;
--- 3163,3185 ----
  mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
  		    va_list args)
  {
+   struct mips_opcode *mo;
    struct mips_cl_insn insn;
    bfd_reloc_code_real_type r[3]
      = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
  
!   mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
!   assert (mo);
!   assert (strcmp (name, mo->name) == 0);
  
!   while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
!     {
!       ++mo;
!       assert (mo->name);
!       assert (strcmp (name, mo->name) == 0);
!     }
  
+   create_insn (&insn, mo);
    for (;;)
      {
        int c;
*************** static void
*** 3363,3368 ****
--- 3305,3311 ----
  macro_build_lui (expressionS *ep, int regnum)
  {
    expressionS high_expr;
+   const struct mips_opcode *mo;
    struct mips_cl_insn insn;
    bfd_reloc_code_real_type r[3]
      = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
*************** macro_build_lui (expressionS *ep, int re
*** 3394,3403 ****
        *r = BFD_RELOC_HI16_S;
      }
  
!   insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name);
!   assert (insn.insn_mo);
!   assert (strcmp (name, insn.insn_mo->name) == 0);
!   assert (strcmp (fmt, insn.insn_mo->args) == 0);
  
    insn.insn_opcode = insn.insn_mo->match;
    INSERT_OPERAND (RT, insn, regnum);
--- 3337,3346 ----
        *r = BFD_RELOC_HI16_S;
      }
  
!   mo = hash_find (op_hash, name);
!   assert (strcmp (name, mo->name) == 0);
!   assert (strcmp (fmt, mo->args) == 0);
!   create_insn (&insn, mo);
  
    insn.insn_opcode = insn.insn_mo->match;
    INSERT_OPERAND (RT, insn, regnum);
*************** mips_ip (char *str, struct mips_cl_insn 
*** 8018,8025 ****
  	    }
  	}
  
!       ip->insn_mo = insn;
!       ip->insn_opcode = insn->match;
        insn_error = NULL;
        for (args = insn->args;; ++args)
  	{
--- 7961,7967 ----
  	    }
  	}
  
!       create_insn (ip, insn);
        insn_error = NULL;
        for (args = insn->args;; ++args)
  	{
*************** mips16_ip (char *str, struct mips_cl_ins
*** 9123,9131 ****
      {
        assert (strcmp (insn->name, str) == 0);
  
!       ip->insn_mo = insn;
!       ip->insn_opcode = insn->match;
!       ip->use_extend = FALSE;
        imm_expr.X_op = O_absent;
        imm_reloc[0] = BFD_RELOC_UNUSED;
        imm_reloc[1] = BFD_RELOC_UNUSED;
--- 9065,9071 ----
      {
        assert (strcmp (insn->name, str) == 0);
  
!       create_insn (ip, insn);
        imm_expr.X_op = O_absent;
        imm_reloc[0] = BFD_RELOC_UNUSED;
        imm_reloc[1] = BFD_RELOC_UNUSED;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11]
  2005-03-08 14:56       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Richard Sandiford
@ 2005-03-08 15:00         ` Richard Sandiford
  2005-03-08 15:05           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Richard Sandiford
  2005-03-08 19:12           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Eric Christopher
  2005-03-08 19:12         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:00 UTC (permalink / raw)
  To: binutils

After the previous patch, the branch delay-slot code no longer needs
to check whether we've inserted any nops before the branch.  If we did
insert some nops, they will already be in the history buffer, and will
already be marked as fixed.

It's also not necessary to check whether the previous instruction was
a delayed branch.  If such a branch occurs outside a noreorder block,
we will always emit a delay slot for it, so we'll never see the
branch in history[0].  If a branch occurs _inside_ a noreorder block,
we wouldn't use it for that very reason.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard



	* config/tc-mips.c (append_insn): Remove now-redundant nops != 0
	check from branch delay code.  Remove unnecessary check for branches.

diff -crpN gas.6/config/tc-mips.c gas/config/tc-mips.c
*** gas.6/config/tc-mips.c	2005-03-08 10:30:43.161925269 +0000
--- gas/config/tc-mips.c	2005-03-08 10:40:48.973789602 +0000
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2472,2480 ****
  	      /* If we have seen .set volatile or .set nomove, don't
  		 optimize.  */
  	      || mips_opts.nomove != 0
- 	      /* If we had to emit any NOP instructions, then we
- 		 already know we can not swap.  */
- 	      || nops != 0
  	      /* We can't swap if the previous instruction's position
  		 is fixed.  */
  	      || history[0].fixed_p
--- 2472,2477 ----
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2536,2546 ****
                    /* Itbl support may require additional care here.  */
  		  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY)
  		  && ! cop_mem_interlocks)
- 	      /* We can not swap with a branch instruction.  */
- 	      || (prev_pinfo
- 		  & (INSN_UNCOND_BRANCH_DELAY
- 		     | INSN_COND_BRANCH_DELAY
- 		     | INSN_COND_BRANCH_LIKELY))
  	      /* We do not swap with a trap instruction, since it
  		 complicates trap handlers to have the trap
  		 instruction be in a delay slot.  */
--- 2533,2538 ----

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11]
  2005-03-08 15:00         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Richard Sandiford
@ 2005-03-08 15:05           ` Richard Sandiford
  2005-03-08 15:06             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Richard Sandiford
  2005-03-08 19:18             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Eric Christopher
  2005-03-08 19:12           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:05 UTC (permalink / raw)
  To: binutils

Finally, the meat of the new infrastructure...

There are currently three places in gas that check whether an instruction
has delay slots:

    - append_insn, when deciding whether to insert nops
    - append_insn, when deciding how to fill a branch delay slot
    - mips_emit_delays

If the instruction has two delay slots, there are usually two pieces
of code for it, one for gaps of 1 instruction and one for gaps of 2.

This patch factors all the errata and delay slot logic into new
functions so that each condition is only checked in one place.
It also removes the current hard-coded assumption that no more
than 2 nops will be needed.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.c (MAX_NOPS): New macro.
	(history): Resize to 1 + MAX_NOPS.
	(fix_vr4120_class): New enumeration.
	(vr4120_conflicts): New variable.
	(init_vr4120_conflicts): New function.
	(md_begin): Call it.
	(insn_uses_reg): Constify first argument.
	(classify_vr4120_insn, nops_between, nops_for_insn, nops_for_sequence)
	(nops_for_insn_or_target): New functions.
	(append_insn): Use the new nops_for_* functions instead of inline
	delay checks.  Generalize prev_nop_frag handling to handle an
	arbitrary history length.  Insert nops into the history buffer
	once the number of nops in prev_nop_frag is fixed.
	(emit_delays): Use nops_for_insn instead of inline delay checks.

diff -crpN gas.7/config/tc-mips.c gas/config/tc-mips.c
*** gas.7/config/tc-mips.c	2005-03-08 10:40:48.973789602 +0000
--- gas/config/tc-mips.c	2005-03-08 10:54:16.425038354 +0000
*************** static int mips_optimize = 2;
*** 557,564 ****
     equivalent to seeing no -g option at all.  */
  static int mips_debug = 0;
  
! /* A list of previous instructions, with index 0 being the most recent.  */
! static struct mips_cl_insn history[2];
  
  /* Nop instructions used by emit_nop.  */
  static struct mips_cl_insn nop_insn, mips16_nop_insn;
--- 557,572 ----
     equivalent to seeing no -g option at all.  */
  static int mips_debug = 0;
  
! /* The maximum number of NOPs needed to satisfy a hardware hazard
!    or processor errata.  */
! #define MAX_NOPS 2
! 
! /* 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];
  
  /* Nop instructions used by emit_nop.  */
  static struct mips_cl_insn nop_insn, mips16_nop_insn;
*************** static const unsigned int mips16_to_32_r
*** 631,636 ****
--- 639,662 ----
    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;
  
  /* We don't relax branches by default, since this causes us to expand
*************** emit_nop (void)
*** 1285,1290 ****
--- 1311,1360 ----
    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.  */
  
*************** md_begin (void)
*** 1513,1518 ****
--- 1583,1591 ----
  
    if (! ECOFF_DEBUGGING)
      md_obj_begin ();
+ 
+   if (mips_fix_vr4120)
+     init_vr4120_conflicts ();
  }
  
  void
*************** fixup_has_matching_lo_p (fixS *fixp)
*** 1604,1610 ****
     of register.  */
  
  static int
! insn_uses_reg (struct mips_cl_insn *ip, unsigned int reg,
  	       enum mips_regclass class)
  {
    if (class == MIPS16_REG)
--- 1677,1683 ----
     of register.  */
  
  static int
! insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
  	       enum mips_regclass class)
  {
    if (class == MIPS16_REG)
*************** relax_end (void)
*** 1773,1778 ****
--- 1846,2068 ----
    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
+ nops_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 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_NOPS; i++)
+     if (!history[i].noreorder_p)
+       {
+ 	tmp_nops = nops_between (history + i, insn) - i;
+ 	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;
+ 
+   va_start (args, history);
+   cursor = buffer + num_insns;
+   memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
+   while (cursor > buffer)
+     *--cursor = *va_arg (args, const struct mips_cl_insn *);
+ 
+   nops = nops_for_insn (buffer, NULL);
+   va_end (args);
+   return nops;
+ }
+ 
+ /* Like nops_for_insn, but if INSN is a branch, take into account the
+    worst-case delay for the branch target.  */
+ 
+ static int
+ nops_for_insn_or_target (const struct mips_cl_insn *history,
+ 			 const struct mips_cl_insn *insn)
+ {
+   int nops, tmp_nops;
+ 
+   nops = nops_for_insn (history, insn);
+   if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
+ 			      | INSN_COND_BRANCH_DELAY
+ 			      | INSN_COND_BRANCH_LIKELY))
+     {
+       tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
+       if (tmp_nops > nops)
+ 	nops = tmp_nops;
+     }
+   else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
+     {
+       tmp_nops = nops_for_sequence (1, history, insn);
+       if (tmp_nops > nops)
+ 	nops = tmp_nops;
+     }
+   return nops;
+ }
+ 
  /* Output an instruction.  IP is the instruction information.
     ADDRESS_EXPR is an operand of the instruction to be used with
     RELOC_TYPE.  */
*************** append_insn (struct mips_cl_insn *ip, ex
*** 1782,1788 ****
  	     bfd_reloc_code_real_type *reloc_type)
  {
    register unsigned long prev_pinfo, pinfo;
-   int nops = 0;
    relax_stateT prev_insn_frag_type = 0;
    bfd_boolean relaxed_branch = FALSE;
  
--- 2072,2077 ----
*************** append_insn (struct mips_cl_insn *ip, ex
*** 1792,2084 ****
    prev_pinfo = history[0].insn_mo->pinfo;
    pinfo = ip->insn_mo->pinfo;
  
!   if (mips_relax.sequence != 2
!       && (!mips_opts.noreorder || prev_nop_frag != NULL))
      {
!       int prev_prev_nop;
! 
!       /* If the previous insn required any delay slots, see if we need
! 	 to insert a NOP or two.  There are eight kinds of possible
! 	 hazards, of which an instruction can have at most one type.
! 	 (1) a load from memory delay
! 	 (2) a load from a coprocessor delay
! 	 (3) an unconditional branch delay
! 	 (4) a conditional branch delay
! 	 (5) a move to coprocessor register delay
! 	 (6) a load coprocessor register from memory delay
! 	 (7) a coprocessor condition code delay
! 	 (8) a HI/LO special register delay
! 
! 	 There are a lot of optimizations we could do that we don't.
  	 In particular, we do not, in general, reorder instructions.
  	 If you use gcc with optimization, it will reorder
  	 instructions and generally do much more optimization then we
  	 do here; repeating all that work in the assembler would only
  	 benefit hand written assembly code, and does not seem worth
  	 it.  */
! 
!       /* The previous insn might require a delay slot, depending upon
! 	 the contents of the current insn.  */
!       if (! mips_opts.mips16
! 	  && (((prev_pinfo & INSN_LOAD_MEMORY_DELAY)
! 	       && ! gpr_interlocks)
! 	      || ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
! 		  && ! cop_interlocks)))
! 	{
! 	  /* A load from a coprocessor or from memory.  All load
! 	     delays 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 (mips_optimize == 0
! 	      || insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
! 				MIPS_GR_REG))
! 	    ++nops;
! 	}
!       else if (! mips_opts.mips16
! 	       && (((prev_pinfo & INSN_COPROC_MOVE_DELAY)
! 		    && ! cop_interlocks)
! 		   || ((prev_pinfo & INSN_COPROC_MEMORY_DELAY)
! 		       && ! cop_mem_interlocks)))
! 	{
! 	  /* A generic coprocessor delay.  The previous instruction
! 	     modified a coprocessor general or control register.  If
! 	     it modified a control register, we need to avoid any
! 	     coprocessor instruction (this is probably not always
! 	     required, but it sometimes is).  If it modified a general
! 	     register, we avoid using that register.
! 
! 	     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!  */
! 	  if (prev_pinfo & INSN_WRITE_FPR_T)
! 	    {
! 	      if (mips_optimize == 0
! 		  || insn_uses_reg (ip, EXTRACT_OPERAND (FT, history[0]),
! 				    MIPS_FP_REG))
! 		++nops;
! 	    }
! 	  else if (prev_pinfo & INSN_WRITE_FPR_S)
! 	    {
! 	      if (mips_optimize == 0
! 		  || insn_uses_reg (ip, EXTRACT_OPERAND (FS, history[0]),
! 				    MIPS_FP_REG))
! 		++nops;
! 	    }
! 	  else
! 	    {
! 	      /* We don't know exactly what the previous instruction
! 		 does.  If the current instruction uses a coprocessor
! 		 register, we must insert a NOP.  If previous
! 		 instruction may set the condition codes, and the
! 		 current instruction uses them, we must insert two
! 		 NOPS.  */
!               /* Itbl support may require additional care here.  */
! 	      if (mips_optimize == 0
! 		  || ((prev_pinfo & INSN_WRITE_COND_CODE)
! 		      && (pinfo & INSN_READ_COND_CODE)))
! 		nops += 2;
! 	      else if (pinfo & INSN_COP)
! 		++nops;
! 	    }
! 	}
!       else if (! mips_opts.mips16
! 	       && (prev_pinfo & INSN_WRITE_COND_CODE)
!                && ! cop_interlocks)
! 	{
! 	  /* The previous instruction sets the coprocessor condition
! 	     codes, but does not require a general coprocessor delay
! 	     (this means it is a floating point comparison
! 	     instruction).  If this instruction uses the condition
! 	     codes, we need to insert a single NOP.  */
! 	  /* Itbl support may require additional care here.  */
! 	  if (mips_optimize == 0
! 	      || (pinfo & INSN_READ_COND_CODE))
! 	    ++nops;
! 	}
! 
!       /* If we're fixing up mfhi/mflo for the r7000 and the
! 	 previous insn was an mfhi/mflo and the current insn
! 	 reads the register that the mfhi/mflo wrote to, then
! 	 insert two nops.  */
! 
!       else if (mips_7000_hilo_fix
! 	       && MF_HILO_INSN (prev_pinfo)
! 	       && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
! 				 MIPS_GR_REG))
! 	{
! 	  nops += 2;
! 	}
! 
!       /* If we're fixing up mfhi/mflo for the r7000 and the
! 	 2nd previous insn was an mfhi/mflo and the current insn
! 	 reads the register that the mfhi/mflo wrote to, then
! 	 insert one nop.  */
! 
!       else if (mips_7000_hilo_fix
! 	       && MF_HILO_INSN (history[1].insn_opcode)
! 	       && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[1]),
! 				 MIPS_GR_REG))
! 
! 	{
! 	  ++nops;
! 	}
! 
!       else if (prev_pinfo & INSN_READ_LO)
! 	{
! 	  /* The previous instruction reads the LO register; if the
! 	     current instruction writes to the LO register, we must
! 	     insert two NOPS.  Some newer processors have interlocks.
! 	     Also the tx39's multiply instructions can be executed
!              immediately after a read from HI/LO (without the delay),
!              though the tx39's divide insns still do require the
! 	     delay.  */
! 	  if (! (hilo_interlocks
! 		 || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
! 	      && (mips_optimize == 0
! 		  || (pinfo & INSN_WRITE_LO)))
! 	    nops += 2;
! 	  /* Most mips16 branch insns don't have a delay slot.
! 	     If a read from LO is immediately followed by a branch
! 	     to a write to LO we have a read followed by a write
! 	     less than 2 insns away.  We assume the target of
! 	     a branch might be a write to LO, and insert a nop
! 	     between a read and an immediately following branch.  */
! 	  else if (mips_opts.mips16
! 		   && (mips_optimize == 0
! 		       || (pinfo & MIPS16_INSN_BRANCH)))
! 	    ++nops;
! 	}
!       else if (history[0].insn_mo->pinfo & INSN_READ_HI)
! 	{
! 	  /* The previous instruction reads the HI register; if the
! 	     current instruction writes to the HI register, we must
! 	     insert a NOP.  Some newer processors have interlocks.
! 	     Also the note tx39's multiply above.  */
! 	  if (! (hilo_interlocks
! 		 || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
! 	      && (mips_optimize == 0
! 		  || (pinfo & INSN_WRITE_HI)))
! 	    nops += 2;
! 	  /* Most mips16 branch insns don't have a delay slot.
! 	     If a read from HI is immediately followed by a branch
! 	     to a write to HI we have a read followed by a write
! 	     less than 2 insns away.  We assume the target of
! 	     a branch might be a write to HI, and insert a nop
! 	     between a read and an immediately following branch.  */
! 	  else if (mips_opts.mips16
! 		   && (mips_optimize == 0
! 		       || (pinfo & MIPS16_INSN_BRANCH)))
! 	    ++nops;
! 	}
! 
!       /* If the previous instruction was in a noreorder section, then
!          we don't want to insert the nop after all.  */
!       /* Itbl support may require additional care here.  */
!       if (history[0].noreorder_p)
! 	nops = 0;
! 
!       /* There are two cases which require two intervening
! 	 instructions: 1) setting the condition codes using a move to
! 	 coprocessor instruction which requires a general coprocessor
! 	 delay and then reading the condition codes 2) reading the HI
! 	 or LO register and then writing to it (except on processors
! 	 which have interlocks).  If we are not already emitting a NOP
! 	 instruction, we must check for these cases compared to the
! 	 instruction previous to the previous instruction.  */
!       if ((! mips_opts.mips16
! 	   && (history[1].insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
! 	   && (history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
! 	   && (pinfo & INSN_READ_COND_CODE)
! 	   && ! cop_interlocks)
! 	  || ((history[1].insn_mo->pinfo & INSN_READ_LO)
! 	      && (pinfo & INSN_WRITE_LO)
! 	      && ! (hilo_interlocks
! 		    || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT))))
! 	  || ((history[1].insn_mo->pinfo & INSN_READ_HI)
! 	      && (pinfo & INSN_WRITE_HI)
! 	      && ! (hilo_interlocks
! 		    || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))))
! 	prev_prev_nop = 1;
!       else
! 	prev_prev_nop = 0;
! 
!       if (history[1].noreorder_p)
! 	prev_prev_nop = 0;
! 
!       if (prev_prev_nop && nops == 0)
! 	++nops;
! 
!       if (mips_fix_vr4120 && history[0].insn_mo->name)
! 	{
! 	  /* We're out of bits in pinfo, so we must resort to string
! 	     ops here.  Shortcuts are selected based on opcodes being
! 	     limited to the VR4120 instruction set.  */
! 	  int min_nops = 0;
! 	  const char *pn = history[0].insn_mo->name;
! 	  const char *tn = ip->insn_mo->name;
! 	  if (strncmp (pn, "macc", 4) == 0
! 	      || strncmp (pn, "dmacc", 5) == 0)
! 	    {
! 	      /* Errata 21 - [D]DIV[U] after [D]MACC */
! 	      if (strstr (tn, "div"))
! 		min_nops = 1;
! 
! 	      /* 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."  */
! 	      if (strncmp (tn, "mult", 4) == 0
! 		  || strncmp (tn, "dmult", 5) == 0)
! 		min_nops = 1;
! 
! 	      /* Errata 23 - Continuous DMULT[U]/DMACC instructions.
! 		 Applies on top of VR4181A MD(1) errata.  */
! 	      if (pn[0] == 'd' && strncmp (tn, "dmacc", 5) == 0)
! 		min_nops = 1;
! 
! 	      /* Errata 24 - MT{LO,HI} after [D]MACC */
! 	      if (strcmp (tn, "mtlo") == 0
! 		  || strcmp (tn, "mthi") == 0)
! 		min_nops = 1;
! 	    }
! 	  else if (strncmp (pn, "dmult", 5) == 0
! 		   && (strncmp (tn, "dmult", 5) == 0
! 		       || strncmp (tn, "dmacc", 5) == 0))
! 	    {
! 	      /* Here is the rest of errata 23.  */
! 	      min_nops = 1;
! 	    }
! 	  else if ((strncmp (pn, "dmult", 5) == 0 || strstr (pn, "div"))
! 		   && (strncmp (tn, "macc", 4) == 0
! 		       || strncmp (tn, "dmacc", 5) == 0))
! 	    {
! 	      /* 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.".  This partly overlaps
! 		 the workaround for errata 23.  */
! 	      min_nops = 1;
! 	    }
! 	  if (nops < min_nops)
! 	    nops = min_nops;
! 	}
! 
!       /* If we are being given a nop instruction, don't bother with
! 	 one of the nops we would otherwise output.  This will only
! 	 happen when a nop instruction is used with mips_optimize set
! 	 to 0.  */
!       if (nops > 0
! 	  && ! mips_opts.noreorder
! 	  && ip->insn_opcode == (unsigned) (mips_opts.mips16 ? 0x6500 : 0))
! 	--nops;
! 
!       /* Now emit the right number of NOP instructions.  */
!       if (nops > 0 && ! mips_opts.noreorder)
  	{
  	  fragS *old_frag;
  	  unsigned long old_frag_offset;
--- 2081,2099 ----
    prev_pinfo = history[0].insn_mo->pinfo;
    pinfo = ip->insn_mo->pinfo;
  
!   if (mips_relax.sequence != 2 && !mips_opts.noreorder)
      {
!       /* There are a lot of optimizations we could do that we don't.
  	 In particular, we do not, in general, reorder instructions.
  	 If you use gcc with optimization, it will reorder
  	 instructions and generally do much more optimization then we
  	 do here; repeating all that work in the assembler would only
  	 benefit hand written assembly code, and does not seem worth
  	 it.  */
!       int nops = (mips_optimize == 0
! 		  ? nops_for_insn (history, NULL)
! 		  : nops_for_insn_or_target (history, ip));
!       if (nops > 0)
  	{
  	  fragS *old_frag;
  	  unsigned long old_frag_offset;
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2123,2164 ****
  	    ecoff_fix_loc (old_frag, old_frag_offset);
  #endif
  	}
!       else if (prev_nop_frag != NULL)
! 	{
! 	  /* We have a frag holding nops we may be able to remove.  If
!              we don't need any nops, we can decrease the size of
!              prev_nop_frag by the size of one instruction.  If we do
!              need some nops, we count them in prev_nops_required.  */
! 	  if (prev_nop_frag_since == 0)
! 	    {
! 	      if (nops == 0)
! 		{
! 		  prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
! 		  --prev_nop_frag_holds;
! 		}
! 	      else
! 		prev_nop_frag_required += nops;
! 	    }
! 	  else
! 	    {
! 	      if (prev_prev_nop == 0)
! 		{
! 		  prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
! 		  --prev_nop_frag_holds;
! 		}
! 	      else
! 		++prev_nop_frag_required;
! 	    }
! 
! 	  if (prev_nop_frag_holds <= prev_nop_frag_required)
! 	    prev_nop_frag = NULL;
  
! 	  ++prev_nop_frag_since;
  
! 	  /* Sanity check: by the time we reach the second instruction
!              after prev_nop_frag, we should have used up all the nops
!              one way or another.  */
! 	  assert (prev_nop_frag_since <= 1 || prev_nop_frag == NULL);
  	}
      }
  
--- 2138,2169 ----
  	    ecoff_fix_loc (old_frag, old_frag_offset);
  #endif
  	}
!     }
!   else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
!     {
!       /* Work out how many nops in prev_nop_frag are needed by IP.  */
!       int nops = nops_for_insn_or_target (history, ip);
!       assert (nops <= prev_nop_frag_holds);
  
!       /* Enforce NOPS as a minimum.  */
!       if (nops > prev_nop_frag_required)
! 	prev_nop_frag_required = nops;
  
!       if (prev_nop_frag_holds == prev_nop_frag_required)
! 	{
! 	  /* Settle for the current number of nops.  Update the history
! 	     accordingly (for the benefit of any future .set reorder code).  */
! 	  prev_nop_frag = NULL;
! 	  insert_into_history (prev_nop_frag_since,
! 			       prev_nop_frag_holds, NOP_INSN);
! 	}
!       else
! 	{
! 	  /* Allow this instruction to replace one of the nops that was
! 	     tentatively added to prev_nop_frag.  */
! 	  prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
! 	  prev_nop_frag_holds--;
! 	  prev_nop_frag_since++;
  	}
      }
  
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2511,2538 ****
  	      || (! mips_opts.mips16
  		  && (pinfo & INSN_READ_COND_CODE)
  		  && ! cop_interlocks)
! 	      /* We can not swap with an instruction that requires a
! 		 delay slot, because the target of the branch might
! 		 interfere with that instruction.  */
! 	      || (! mips_opts.mips16
! 		  && (prev_pinfo
!               /* Itbl support may require additional care here.  */
! 		      & (INSN_LOAD_COPROC_DELAY
! 			 | INSN_COPROC_MOVE_DELAY
! 			 | INSN_WRITE_COND_CODE))
! 		  && ! cop_interlocks)
! 	      || (! (hilo_interlocks
! 		     || (mips_opts.arch == CPU_R3900 && (pinfo & INSN_MULT)))
! 		  && (prev_pinfo
! 		      & (INSN_READ_LO
! 			 | INSN_READ_HI)))
! 	      || (! mips_opts.mips16
! 		  && (prev_pinfo & INSN_LOAD_MEMORY_DELAY)
! 		  && ! gpr_interlocks)
! 	      || (! mips_opts.mips16
!                   /* Itbl support may require additional care here.  */
! 		  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY)
! 		  && ! cop_mem_interlocks)
  	      /* We do not swap with a trap instruction, since it
  		 complicates trap handlers to have the trap
  		 instruction be in a delay slot.  */
--- 2516,2527 ----
  	      || (! mips_opts.mips16
  		  && (pinfo & INSN_READ_COND_CODE)
  		  && ! cop_interlocks)
! 	      /* Check for conflicts between the branch and the instructions
! 		 before the candidate delay slot.  */
! 	      || nops_for_insn (history + 1, ip) > 0
! 	      /* Check for conflicts between the swapped sequence and the
! 		 target of the branch.  */
! 	      || nops_for_sequence (2, history + 1, ip, history) > 0
  	      /* We do not swap with a trap instruction, since it
  		 complicates trap handlers to have the trap
  		 instruction be in a delay slot.  */
*************** append_insn (struct mips_cl_insn *ip, ex
*** 2606,2623 ****
  	      || (mips_opts.mips16
  		  && (pinfo & MIPS16_INSN_WRITE_31)
  		  && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
- 	      /* If the previous previous instruction has a load
- 		 delay, and sets a register that the branch reads, we
- 		 can not swap.  */
- 	      || (! mips_opts.mips16
-               /* Itbl support may require additional care here.  */
- 		  && (((history[1].insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
- 		       && ! cop_interlocks)
- 		      || ((history[1].insn_mo->pinfo
- 			   & INSN_LOAD_MEMORY_DELAY)
- 			  && ! gpr_interlocks))
- 		  && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[1]),
- 				    MIPS_GR_REG))
  	      /* If one instruction sets a condition code and the
                   other one uses a condition code, we can not swap.  */
  	      || ((pinfo & INSN_READ_COND_CODE)
--- 2595,2600 ----
*************** mips_emit_delays (bfd_boolean insns)
*** 2739,2807 ****
  {
    if (! mips_opts.noreorder)
      {
!       int nops;
! 
!       nops = 0;
!       if ((! mips_opts.mips16
! 	   && ((history[0].insn_mo->pinfo
! 		& (INSN_LOAD_COPROC_DELAY
! 		   | INSN_COPROC_MOVE_DELAY
! 		   | INSN_WRITE_COND_CODE))
! 	       && ! cop_interlocks))
! 	  || (! hilo_interlocks
! 	      && (history[0].insn_mo->pinfo
! 		  & (INSN_READ_LO
! 		     | INSN_READ_HI)))
! 	  || (! mips_opts.mips16
! 	      && (history[0].insn_mo->pinfo & INSN_LOAD_MEMORY_DELAY)
! 	      && ! gpr_interlocks)
! 	  || (! mips_opts.mips16
! 	      && (history[0].insn_mo->pinfo & INSN_COPROC_MEMORY_DELAY)
! 	      && ! cop_mem_interlocks))
! 	{
! 	  /* Itbl support may require additional care here.  */
! 	  ++nops;
! 	  if ((! mips_opts.mips16
! 	       && ((history[0].insn_mo->pinfo & INSN_WRITE_COND_CODE)
! 		   && ! cop_interlocks))
! 	      || (! hilo_interlocks
! 		  && ((history[0].insn_mo->pinfo & INSN_READ_HI)
! 		      || (history[0].insn_mo->pinfo & INSN_READ_LO))))
! 	    ++nops;
! 
! 	  if (history[0].noreorder_p)
! 	    nops = 0;
! 	}
!       else if ((! mips_opts.mips16
! 		&& ((history[1].insn_mo->pinfo & INSN_WRITE_COND_CODE)
! 		    && ! cop_interlocks))
! 	       || (! hilo_interlocks
! 		   && ((history[1].insn_mo->pinfo & INSN_READ_HI)
! 		       || (history[1].insn_mo->pinfo & INSN_READ_LO))))
! 	{
! 	  /* Itbl support may require additional care here.  */
! 	  if (! history[1].noreorder_p)
! 	    ++nops;
! 	}
! 
!       if (mips_fix_vr4120 && history[0].insn_mo->name)
! 	{
! 	  int min_nops = 0;
! 	  const char *pn = history[0].insn_mo->name;
! 	  if (strncmp (pn, "macc", 4) == 0
! 	      || strncmp (pn, "dmacc", 5) == 0
! 	      || strncmp (pn, "dmult", 5) == 0
! 	      || strstr (pn, "div"))
! 	    min_nops = 1;
! 	  if (nops < min_nops)
! 	    nops = min_nops;
! 	}
! 
        if (nops > 0)
  	{
  	  struct insn_label_list *l;
  
! 	  if (insns)
  	    {
  	      /* Record the frag which holds the nop instructions, so
                   that we can remove them if we don't need them.  */
--- 2716,2727 ----
  {
    if (! mips_opts.noreorder)
      {
!       int nops = nops_for_insn (history, NULL);
        if (nops > 0)
  	{
  	  struct insn_label_list *l;
  
! 	  if (insns && mips_optimize != 0)
  	    {
  	      /* Record the frag which holds the nop instructions, so
                   that we can remove them if we don't need them.  */

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11]
  2005-03-08 15:05           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Richard Sandiford
@ 2005-03-08 15:06             ` Richard Sandiford
  2005-03-08 15:10               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Richard Sandiford
  2005-03-08 19:19               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Eric Christopher
  2005-03-08 19:18             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:06 UTC (permalink / raw)
  To: binutils

This obvious patch just factors out some common code into a new function.
The callers will change in the next patch, which is why I'm doing this now.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard



	* config/tc-mips.c (mips_move_labels): New function, taken from...
	(append_insn, mips_emit_delays): ...here.

diff -urpN gas.8/config/tc-mips.c gas/config/tc-mips.c
--- gas.8/config/tc-mips.c	2005-03-08 10:54:16.425038354 +0000
+++ gas/config/tc-mips.c	2005-03-08 11:47:57.177536421 +0000
@@ -1771,6 +1771,26 @@ reg_needs_delay (unsigned int reg)
   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
@@ -2098,7 +2118,6 @@ append_insn (struct mips_cl_insn *ip, ex
 	  fragS *old_frag;
 	  unsigned long old_frag_offset;
 	  int i;
-	  struct insn_label_list *l;
 
 	  old_frag = frag_now;
 	  old_frag_offset = frag_now_fix ();
@@ -2120,18 +2139,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	      frag_grow (40);
 	    }
 
-	  for (l = insn_labels; l != NULL; l = l->next)
-	    {
-	      valueT val;
-
-	      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);
-	    }
+	  mips_move_labels ();
 
 #ifndef NO_ECOFF_DEBUGGING
 	  if (ECOFF_DEBUGGING)
@@ -2719,8 +2727,6 @@ mips_emit_delays (bfd_boolean insns)
       int nops = nops_for_insn (history, NULL);
       if (nops > 0)
 	{
-	  struct insn_label_list *l;
-
 	  if (insns && mips_optimize != 0)
 	    {
 	      /* Record the frag which holds the nop instructions, so
@@ -2743,18 +2749,7 @@ mips_emit_delays (bfd_boolean insns)
 	      frag_new (0);
 	    }
 
-	  for (l = insn_labels; l != NULL; l = l->next)
-	    {
-	      valueT val;
-
-	      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);
-	    }
+	  mips_move_labels ();
 	}
     }
 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11]
  2005-03-08 15:06             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Richard Sandiford
@ 2005-03-08 15:10               ` Richard Sandiford
  2005-03-08 15:12                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Richard Sandiford
  2005-03-08 19:42                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Eric Christopher
  2005-03-08 19:19               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:10 UTC (permalink / raw)
  To: binutils

This patch generalises the end-of-noreorder code in s_mipsset (of which
we have two copies, one for ".set reorder" itself and one for ".set pop").

The current code removes all prev_nop_frag_holds nops from prev_nop_frag
and then sets prev_nop_frag to NULL.  This is safe with our current set
of hazards because prev_nop_frag_required will always be 0 (I'll spare
you the full run-down ;).  However, with this new, more general, interface,
we should cope with cases where:

    prev_nop_frag_holds > prev_nop_frag_required > 0

(which can occur with the VR4133 workarounds).

This patch introduces two new functions, start_noreorder() and
end_noreorder(), for wrapping (potentially nested) noreorder blocks.
end_noreorder() will commit to inserting prev_nop_frag_required nops
before dropping back to .set reorder mode, and will update the history
accordingly.

start_noreorder() subsumes "mips_emit_delays (TRUE)", so this
patch also removes the INSNS parameter from mips_emit_delays and
mips_no_prev_insn.  Note that s_gpword and s_gpdword were wrongly
passing TRUE instead of FALSE here (wrongly because these directives
insert data, not instructions).

md_flush_pending_output is now identical to mips_emit_delays, so the
patch removes the former and uses the latter exclusively.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.h (mips_flush_pending_output): Delete.
	(mips_emit_delays): Declare.
	(md_flush_pending_output): Use mips_emit_delays.
	* config/tc-mips.c (mips_no_prev_insn): Remove parameter; always forget
	the previous instructions.
	(md_begin, append_insn, md_parse_option): Update callers.
	(mips_emit_delay): Remove parameter.  Move INSNS != 0 code to
	start_noreorder.
	(mips_align, s_change_sec, s_cons, s_float_cons, s_gpword)
	(s_gpdword): Update callers.
	(start_noreorder, end_noreorder): New functions.
	(macro, macro2, mips16_macro, s_mipsset): Use them instead of
	manipulating mips_opts or prev_nop_frag directly.
	(mips_flush_pending_output): Delete.

diff -urpN gas.9/config/tc-mips.h gas/config/tc-mips.h
--- gas.9/config/tc-mips.h	2005-03-08 09:07:40.000000000 +0000
+++ gas/config/tc-mips.h	2005-03-08 12:19:23.653556697 +0000
@@ -149,8 +149,8 @@ extern void md_mips_end (void);
 extern void mips_pop_insert (void);
 #define md_pop_insert()		mips_pop_insert()
 
-extern void mips_flush_pending_output (void);
-#define md_flush_pending_output mips_flush_pending_output
+extern void mips_emit_delays (void);
+#define md_flush_pending_output mips_emit_delays
 
 extern void mips_enable_auto_align (void);
 #define md_elf_section_change_hook()	mips_enable_auto_align()
diff -urpN gas.9/config/tc-mips.c gas/config/tc-mips.c
--- gas.9/config/tc-mips.c	2005-03-08 11:47:57.177536421 +0000
+++ gas/config/tc-mips.c	2005-03-08 12:19:23.686551681 +0000
@@ -928,7 +928,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);
@@ -1477,7 +1477,7 @@ md_begin (void)
 				       &zero_address_frag));
     }
 
-  mips_no_prev_insn (FALSE);
+  mips_no_prev_insn ();
 
   mips_gprmask = 0;
   mips_cprmask[0] = 0;
@@ -2664,7 +2664,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  /* If that was an unconditional branch, forget the previous
 	     insn information.  */
 	  if (pinfo & INSN_UNCOND_BRANCH_DELAY)
-	    mips_no_prev_insn (FALSE);
+	    mips_no_prev_insn ();
 	}
       else if (pinfo & INSN_COND_BRANCH_LIKELY)
 	{
@@ -2685,49 +2685,57 @@ append_insn (struct mips_cl_insn *ip, ex
   mips_clear_insn_labels ();
 }
 
-/* This function forgets that there was any previous instruction or
-   label.  If PRESERVE is non-zero, it remembers enough information to
-   know whether nops are needed before a noreorder section.  */
+/* Forget that there was any previous instruction or label.  */
 
 static void
-mips_no_prev_insn (int preserve)
+mips_no_prev_insn (void)
 {
-  size_t i;
- 
-  if (! preserve)
-    {
-      prev_nop_frag = NULL;
-      prev_nop_frag_holds = 0;
-      prev_nop_frag_required = 0;
-      prev_nop_frag_since = 0;
-      for (i = 0; i < ARRAY_SIZE (history); i++)
-	history[i] = (mips_opts.mips16 ? mips16_nop_insn : nop_insn);
-    }
-  else
-    for (i = 0; i < ARRAY_SIZE (history); i++)
-      {
-	history[i].fixed_p = 1;
-	history[i].noreorder_p = 0;
-	history[i].mips16_absolute_jump_p = 0;
-      }
+  prev_nop_frag = NULL;
+  insert_into_history (0, ARRAY_SIZE (history), NOP_INSN);
   mips_clear_insn_labels ();
 }
 
-/* This function must be called whenever we turn on noreorder or emit
-   something other than instructions.  It inserts any NOPS which might
-   be needed by the previous instruction, and clears the information
-   kept for the previous instructions.  The INSNS parameter is true if
-   instructions are to follow.  */
+/* This function must be called before we emit something other than
+   instructions.  It is like mips_no_prev_insn except that it inserts
+   any NOPS that might be needed by previous instructions.  */
 
-static void
-mips_emit_delays (bfd_boolean insns)
+void
+mips_emit_delays (void)
 {
   if (! mips_opts.noreorder)
     {
       int nops = nops_for_insn (history, NULL);
       if (nops > 0)
 	{
-	  if (insns && mips_optimize != 0)
+	  while (nops-- > 0)
+	    add_fixed_insn (NOP_INSN);
+	  mips_move_labels ();
+	}
+    }
+  mips_no_prev_insn ();
+}
+
+/* Start a (possibly nested) noreorder block.  */
+
+static void
+start_noreorder (void)
+{
+  if (mips_opts.noreorder == 0)
+    {
+      unsigned int i;
+      int nops;
+
+      /* None of the instructions before the .set noreorder can be moved.  */
+      for (i = 0; i < ARRAY_SIZE (history); i++)
+	history[i].fixed_p = 1;
+
+      /* Insert any nops that might be needed between the .set noreorder
+	 block and the previous instructions.  We will later remove any
+	 nops that turn out not to be needed.  */
+      nops = nops_for_insn (history, NULL);
+      if (nops > 0)
+	{
+	  if (mips_optimize != 0)
 	    {
 	      /* Record the frag which holds the nop instructions, so
                  that we can remove them if we don't need them.  */
@@ -2741,23 +2749,35 @@ mips_emit_delays (bfd_boolean insns)
 	  for (; nops > 0; --nops)
 	    add_fixed_insn (NOP_INSN);
 
-	  if (insns)
-	    {
-	      /* Move on to a new frag, so that it is safe to simply
-                 decrease the size of prev_nop_frag.  */
-	      frag_wane (frag_now);
-	      frag_new (0);
-	    }
-
+	  /* Move on to a new frag, so that it is safe to simply
+	     decrease the size of prev_nop_frag.  */
+	  frag_wane (frag_now);
+	  frag_new (0);
 	  mips_move_labels ();
 	}
+      mips16_mark_labels ();
+      mips_clear_insn_labels ();
     }
+  mips_opts.noreorder++;
+  mips_any_noreorder = 1;
+}
 
-  /* Mark instruction labels in mips16 mode.  */
-  if (insns)
-    mips16_mark_labels ();
+/* End a nested noreorder block.  */
 
-  mips_no_prev_insn (insns);
+static void
+end_noreorder (void)
+{
+  mips_opts.noreorder--;
+  if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
+    {
+      /* Commit to inserting prev_nop_frag_required nops and go back to
+	 handling nop insertion the .set reorder way.  */
+      prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required)
+				* (mips_opts.mips16 ? 2 : 4));
+      insert_into_history (prev_nop_frag_since,
+			   prev_nop_frag_required, NOP_INSN);
+      prev_nop_frag = NULL;
+    }
 }
 
 /* Set up global variables for the start of a new macro.  */
@@ -4061,9 +4081,7 @@ macro (struct mips_cl_insn *ip)
 	 sub v0,$zero,$a0
 	 */
 
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
 
       expr1.X_add_number = 8;
       macro_build (&expr1, "bgez", "s,p", sreg);
@@ -4073,7 +4091,7 @@ macro (struct mips_cl_insn *ip)
 	move_register (dreg, sreg);
       macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
 
-      --mips_opts.noreorder;
+      end_noreorder ();
       break;
 
     case M_ADD_I:
@@ -4581,9 +4599,7 @@ macro (struct mips_cl_insn *ip)
 	  break;
 	}
 
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       if (mips_trap)
 	{
 	  macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
@@ -4617,7 +4633,7 @@ macro (struct mips_cl_insn *ip)
 	  macro_build (NULL, "teq", "s,t,q", sreg, AT, 6);
 	  /* We want to close the noreorder block as soon as possible, so
 	     that later insns are available for delay slot filling.  */
-	  --mips_opts.noreorder;
+	  end_noreorder ();
 	}
       else
 	{
@@ -4627,7 +4643,7 @@ macro (struct mips_cl_insn *ip)
 
 	  /* We want to close the noreorder block as soon as possible, so
 	     that later insns are available for delay slot filling.  */
-	  --mips_opts.noreorder;
+	  end_noreorder ();
 
 	  macro_build (NULL, "break", "c", 6);
 	}
@@ -4722,16 +4738,14 @@ macro (struct mips_cl_insn *ip)
       s = "ddivu";
       s2 = "mfhi";
     do_divu3:
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       if (mips_trap)
 	{
 	  macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
 	  macro_build (NULL, s, "z,s,t", sreg, treg);
 	  /* We want to close the noreorder block as soon as possible, so
 	     that later insns are available for delay slot filling.  */
-	  --mips_opts.noreorder;
+	  end_noreorder ();
 	}
       else
 	{
@@ -4741,7 +4755,7 @@ macro (struct mips_cl_insn *ip)
 
 	  /* We want to close the noreorder block as soon as possible, so
 	     that later insns are available for delay slot filling.  */
-	  --mips_opts.noreorder;
+	  end_noreorder ();
 	  macro_build (NULL, "break", "c", 7);
 	}
       macro_build (NULL, s2, "d", dreg);
@@ -6669,9 +6683,7 @@ macro2 (struct mips_cl_insn *ip)
       dbl = 1;
     case M_MULO:
     do_mulo:
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       used_at = 1;
       if (imm)
 	load_register (AT, &imm_expr, dbl);
@@ -6688,7 +6700,7 @@ macro2 (struct mips_cl_insn *ip)
 	  macro_build (NULL, "nop", "", 0);
 	  macro_build (NULL, "break", "c", 6);
 	}
-      --mips_opts.noreorder;
+      end_noreorder ();
       macro_build (NULL, "mflo", "d", dreg);
       break;
 
@@ -6702,9 +6714,7 @@ macro2 (struct mips_cl_insn *ip)
       dbl = 1;
     case M_MULOU:
     do_mulou:
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       used_at = 1;
       if (imm)
 	load_register (AT, &imm_expr, dbl);
@@ -6721,7 +6731,7 @@ macro2 (struct mips_cl_insn *ip)
 	  macro_build (NULL, "nop", "", 0);
 	  macro_build (NULL, "break", "c", 6);
 	}
-      --mips_opts.noreorder;
+      end_noreorder ();
       break;
 
     case M_DROL:
@@ -7186,9 +7196,7 @@ macro2 (struct mips_cl_insn *ip)
        * Is the double cfc1 instruction a bug in the mips assembler;
        * or is there a reason for it?
        */
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       macro_build (NULL, "cfc1", "t,G", treg, RA);
       macro_build (NULL, "cfc1", "t,G", treg, RA);
       macro_build (NULL, "nop", "");
@@ -7202,7 +7210,7 @@ macro2 (struct mips_cl_insn *ip)
 		   dreg, sreg);
       macro_build (NULL, "ctc1", "t,G", treg, RA);
       macro_build (NULL, "nop", "");
-      --mips_opts.noreorder;
+      end_noreorder ();
       break;
 
     case M_ULH:
@@ -7442,9 +7450,7 @@ mips16_macro (struct mips_cl_insn *ip)
     case M_REM_3:
       s = "mfhi";
     do_div3:
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build (&expr1, "bnez", "x,p", yreg);
@@ -7454,7 +7460,7 @@ mips16_macro (struct mips_cl_insn *ip)
          since that causes an overflow.  We should do that as well,
          but I don't see how to do the comparisons without a temporary
          register.  */
-      --mips_opts.noreorder;
+      end_noreorder ();
       macro_build (NULL, s, "x", zreg);
       break;
 
@@ -7474,14 +7480,12 @@ mips16_macro (struct mips_cl_insn *ip)
       s = "ddivu";
       s2 = "mfhi";
     do_divu3:
-      mips_emit_delays (TRUE);
-      ++mips_opts.noreorder;
-      mips_any_noreorder = 1;
+      start_noreorder ();
       macro_build (NULL, s, "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build (&expr1, "bnez", "x,p", yreg);
       macro_build (NULL, "break", "6", 7);
-      --mips_opts.noreorder;
+      end_noreorder ();
       macro_build (NULL, s2, "x", zreg);
       break;
 
@@ -10194,12 +10198,12 @@ md_parse_option (int c, char *arg)
 
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
-      mips_no_prev_insn (FALSE);
+      mips_no_prev_insn ();
       break;
 
     case OPTION_NO_MIPS16:
       mips_opts.mips16 = 0;
-      mips_no_prev_insn (FALSE);
+      mips_no_prev_insn ();
       break;
 
     case OPTION_MIPS3D:
@@ -11058,7 +11062,7 @@ get_symbol (void)
 static void
 mips_align (int to, int fill, symbolS *label)
 {
-  mips_emit_delays (FALSE);
+  mips_emit_delays ();
   frag_align (to, fill, 0);
   record_alignment (now_seg, to);
   if (label != NULL)
@@ -11120,13 +11124,6 @@ s_align (int x ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
-void
-mips_flush_pending_output (void)
-{
-  mips_emit_delays (FALSE);
-  mips_clear_insn_labels ();
-}
-
 static void
 s_change_sec (int sec)
 {
@@ -11142,7 +11139,7 @@ s_change_sec (int sec)
   obj_elf_section_change_hook ();
 #endif
 
-  mips_emit_delays (FALSE);
+  mips_emit_delays ();
   switch (sec)
     {
     case 't':
@@ -11273,7 +11270,7 @@ s_cons (int log_size)
   symbolS *label;
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
-  mips_emit_delays (FALSE);
+  mips_emit_delays ();
   if (log_size > 0 && auto_align)
     mips_align (log_size, 0, label);
   mips_clear_insn_labels ();
@@ -11287,7 +11284,7 @@ s_float_cons (int type)
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
 
-  mips_emit_delays (FALSE);
+  mips_emit_delays ();
 
   if (auto_align)
     {
@@ -11415,22 +11412,13 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
 
   if (strcmp (name, "reorder") == 0)
     {
-      if (mips_opts.noreorder && prev_nop_frag != NULL)
-	{
-	  /* If we still have pending nops, we can discard them.  The
-	     usual nop handling will insert any that are still
-	     needed.  */
-	  prev_nop_frag->fr_fix -= (prev_nop_frag_holds
-				    * (mips_opts.mips16 ? 2 : 4));
-	  prev_nop_frag = NULL;
-	}
-      mips_opts.noreorder = 0;
+      if (mips_opts.noreorder)
+	end_noreorder ();
     }
   else if (strcmp (name, "noreorder") == 0)
     {
-      mips_emit_delays (TRUE);
-      mips_opts.noreorder = 1;
-      mips_any_noreorder = 1;
+      if (!mips_opts.noreorder)
+	start_noreorder ();
     }
   else if (strcmp (name, "at") == 0)
     {
@@ -11575,16 +11563,9 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
 	  /* If we're changing the reorder mode we need to handle
              delay slots correctly.  */
 	  if (s->options.noreorder && ! mips_opts.noreorder)
-	    mips_emit_delays (TRUE);
+	    start_noreorder ();
 	  else if (! s->options.noreorder && mips_opts.noreorder)
-	    {
-	      if (prev_nop_frag != NULL)
-		{
-		  prev_nop_frag->fr_fix -= (prev_nop_frag_holds
-					    * (mips_opts.mips16 ? 2 : 4));
-		  prev_nop_frag = NULL;
-		}
-	    }
+	    end_noreorder ();
 
 	  mips_opts = s->options;
 	  mips_opts_stack = s->next;
@@ -11924,7 +11905,7 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
     }
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
-  mips_emit_delays (TRUE);
+  mips_emit_delays ();
   if (auto_align)
     mips_align (2, 0, label);
   mips_clear_insn_labels ();
@@ -11960,7 +11941,7 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
     }
 
   label = insn_labels != NULL ? insn_labels->label : NULL;
-  mips_emit_delays (TRUE);
+  mips_emit_delays ();
   if (auto_align)
     mips_align (3, 0, label);
   mips_clear_insn_labels ();

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11]
  2005-03-08 15:10               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Richard Sandiford
@ 2005-03-08 15:12                 ` Richard Sandiford
  2005-03-08 15:16                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11] Richard Sandiford
  2005-03-08 19:43                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Eric Christopher
  2005-03-08 19:42                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Eric Christopher
  1 sibling, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:12 UTC (permalink / raw)
  To: binutils

As promised in the first message, this patch lets gas fill the delay
slots of coprocessor branches with useful insns.  All the real work
to make this possible has already been done by the rest of the series.

The patch adjusts the mips2 branch relaxation tests accordingly and adds
a new test to make sure that the situation mentioned in the old comment
is handled correctly.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard



	* config/tc-mips.c (append_insn): Remove cop_interlocks test from
	branch delay code.

testsuite/
	* gas/mips/relax-swap1-mips[12].d: Expect the delay slots of
	bc1f and bc1t to be filled.
	* gas/mips/branch-misc-3.[sd]: New test.
	* gas/mips/mips.exp: Run it.

diff -urpN gas.10/config/tc-mips.c gas/config/tc-mips.c
--- gas.10/config/tc-mips.c	2005-03-08 12:19:23.000000000 +0000
+++ gas/config/tc-mips.c	2005-03-08 12:48:34.194265580 +0000
@@ -2513,17 +2513,6 @@ append_insn (struct mips_cl_insn *ip, ex
 		 frags for different purposes.  */
 	      || (! mips_opts.mips16
 		  && prev_insn_frag_type == rs_machine_dependent)
-	      /* If the branch reads the condition codes, we don't
-		 even try to swap, because in the sequence
-		   ctc1 $X,$31
-		   INSN
-		   INSN
-		   bc1t LABEL
-		 we can not swap, and I don't feel like handling that
-		 case.  */
-	      || (! mips_opts.mips16
-		  && (pinfo & INSN_READ_COND_CODE)
-		  && ! cop_interlocks)
 	      /* Check for conflicts between the branch and the instructions
 		 before the candidate delay slot.  */
 	      || nops_for_insn (history + 1, ip) > 0
diff -urpN gas.10/testsuite/gas/mips/branch-misc-3.d gas/testsuite/gas/mips/branch-misc-3.d
--- gas.10/testsuite/gas/mips/branch-misc-3.d	1970-01-01 01:00:00.000000000 +0100
+++ gas/testsuite/gas/mips/branch-misc-3.d	2005-03-08 13:14:03.135815087 +0000
@@ -0,0 +1,59 @@
+#as: -march=mips1 -32
+#objdump: -dz
+#name: MIPS coprocessor branches
+
+.*file format .*
+
+Disassembly .*:
+
+0+00 <.*>:
+.*	ctc1	a0,\$31
+.*	b	.*
+.*	nop
+#
+.*	ctc1	a0,\$31
+.*	nop
+.*	nop
+.*	bc1t	.*
+.*	nop
+#
+.*	c\.eq\.s	\$f0,\$f2
+.*	b	.*
+.*	nop
+#
+.*	c\.eq\.s	\$f0,\$f2
+.*	nop
+.*	bc1t	.*
+.*	nop
+#
+.*	ctc1	a0,\$31
+.*	addiu	a1,a1,1
+.*	nop
+.*	bc1t	.*
+.*	nop
+#
+.*	ctc1	a0,\$31
+.*	addiu	a1,a1,1
+.*	addiu	a2,a2,1
+.*	bc1t	.*
+.*	nop
+#
+.*	c\.eq\.s	\$f0,\$f2
+.*	addiu	a1,a1,1
+.*	bc1t	.*
+.*	nop
+#
+.*	ctc1	a0,\$31
+.*	addiu	a1,a1,1
+.*	addiu	a2,a2,1
+.*	bc1t	.*
+.*	addiu	a3,a3,1
+#
+.*	c\.eq\.s	\$f0,\$f2
+.*	addiu	a1,a1,1
+.*	bc1t	.*
+.*	addiu	a2,a2,1
+#
+.*	bc1t	.*
+.*	addiu	a3,a3,1
+#pass
diff -urpN gas.10/testsuite/gas/mips/branch-misc-3.s gas/testsuite/gas/mips/branch-misc-3.s
--- gas.10/testsuite/gas/mips/branch-misc-3.s	1970-01-01 01:00:00.000000000 +0100
+++ gas/testsuite/gas/mips/branch-misc-3.s	2005-03-08 13:10:24.264088647 +0000
@@ -0,0 +1,44 @@
+	# ctc1s and compares shouldn't appear in a branch delay slot.
+	ctc1	$4,$31
+	b	1f
+1:
+	ctc1	$4,$31
+	bc1t	1f
+1:
+	c.eq.s	$f0,$f2
+	b	1f
+1:
+	c.eq.s	$f0,$f2
+	bc1t	1f
+1:
+
+	# The next three branches should have nop-filled slots.
+	ctc1	$4,$31
+	addiu	$5,$5,1
+	bc1t	1f
+1:
+	ctc1	$4,$31
+	addiu	$5,$5,1
+	addiu	$6,$6,1
+	bc1t	1f
+1:
+	c.eq.s	$f0,$f2
+	addiu	$5,$5,1
+	bc1t	1f
+1:
+
+	# ...but a swap is possible in these three.
+	ctc1	$4,$31
+	addiu	$5,$5,1
+	addiu	$6,$6,1
+	addiu	$7,$7,1
+	bc1t	1f
+1:
+	c.eq.s	$f0,$f2
+	addiu	$5,$5,1
+	addiu	$6,$6,1
+	bc1t	1f
+1:
+	addiu	$7,$7,1
+	bc1t	1f
+1:
diff -urpN gas.10/testsuite/gas/mips/relax-swap1-mips1.d gas/testsuite/gas/mips/relax-swap1-mips1.d
--- gas.10/testsuite/gas/mips/relax-swap1-mips1.d	2005-02-28 09:24:25.000000000 +0000
+++ gas/testsuite/gas/mips/relax-swap1-mips1.d	2005-03-08 12:48:34.000000000 +0000
@@ -12,7 +12,7 @@ Disassembly of section \.text:
 0+0008 <[^>]*> lw	at,2\(gp\)
 [ 	]*8: R_MIPS_GOT16	\.text
 0+000c <[^>]*> nop
-0+0010 <[^>]*> addiu	at,at,1000
+0+0010 <[^>]*> addiu	at,at,992
 [ 	]*10: R_MIPS_LO16	\.text
 0+0014 <[^>]*> jr	at
 0+0018 <[^>]*> move	v0,a0
@@ -23,7 +23,7 @@ Disassembly of section \.text:
 0+002c <[^>]*> lw	at,2\(gp\)
 [ 	]*2c: R_MIPS_GOT16	\.text
 0+0030 <[^>]*> nop
-0+0034 <[^>]*> addiu	at,at,1000
+0+0034 <[^>]*> addiu	at,at,992
 [ 	]*34: R_MIPS_LO16	\.text
 0+0038 <[^>]*> jr	at
 0+003c <[^>]*> nop
@@ -32,7 +32,7 @@ Disassembly of section \.text:
 0+0048 <[^>]*> lw	at,2\(gp\)
 [ 	]*48: R_MIPS_GOT16	\.text
 0+004c <[^>]*> nop
-0+0050 <[^>]*> addiu	at,at,1000
+0+0050 <[^>]*> addiu	at,at,992
 [ 	]*50: R_MIPS_LO16	\.text
 0+0054 <[^>]*> jr	at
 0+0058 <[^>]*> sw	v0,0\(a0\)
@@ -45,7 +45,7 @@ Disassembly of section \.text:
 0+0074 <[^>]*> lw	at,2\(gp\)
 [ 	]*74: R_MIPS_GOT16	\.text
 0+0078 <[^>]*> nop
-0+007c <[^>]*> addiu	at,at,1000
+0+007c <[^>]*> addiu	at,at,992
 [ 	]*7c: R_MIPS_LO16	\.text
 0+0080 <[^>]*> jr	at
 0+0084 <[^>]*> nop
@@ -56,7 +56,7 @@ Disassembly of section \.text:
 0+0098 <[^>]*> lw	at,2\(gp\)
 [ 	]*98: R_MIPS_GOT16	\.text
 0+009c <[^>]*> nop
-0+00a0 <[^>]*> addiu	at,at,1000
+0+00a0 <[^>]*> addiu	at,at,992
 [ 	]*a0: R_MIPS_LO16	\.text
 0+00a4 <[^>]*> jr	at
 0+00a8 <[^>]*> move	v0,a0
@@ -69,7 +69,7 @@ Disassembly of section \.text:
 0+00c4 <[^>]*> lw	at,2\(gp\)
 [ 	]*c4: R_MIPS_GOT16	\.text
 0+00c8 <[^>]*> nop
-0+00cc <[^>]*> addiu	at,at,1000
+0+00cc <[^>]*> addiu	at,at,992
 [ 	]*cc: R_MIPS_LO16	\.text
 0+00d0 <[^>]*> jr	at
 0+00d4 <[^>]*> nop
@@ -80,7 +80,7 @@ Disassembly of section \.text:
 0+00e8 <[^>]*> lw	at,2\(gp\)
 [ 	]*e8: R_MIPS_GOT16	\.text
 0+00ec <[^>]*> nop
-0+00f0 <[^>]*> addiu	at,at,1000
+0+00f0 <[^>]*> addiu	at,at,992
 [ 	]*f0: R_MIPS_LO16	\.text
 0+00f4 <[^>]*> jr	at
 0+00f8 <[^>]*> addiu	v0,a0,1
@@ -95,7 +95,7 @@ Disassembly of section \.text:
 0+011c <[^>]*> lw	at,2\(gp\)
 [ 	]*11c: R_MIPS_GOT16	\.text
 0+0120 <[^>]*> nop
-0+0124 <[^>]*> addiu	at,at,1000
+0+0124 <[^>]*> addiu	at,at,992
 [ 	]*124: R_MIPS_LO16	\.text
 0+0128 <[^>]*> jr	at
 0+012c <[^>]*> nop
@@ -108,7 +108,7 @@ Disassembly of section \.text:
 0+0148 <[^>]*> lw	at,2\(gp\)
 [ 	]*148: R_MIPS_GOT16	\.text
 0+014c <[^>]*> nop
-0+0150 <[^>]*> addiu	at,at,1000
+0+0150 <[^>]*> addiu	at,at,992
 [ 	]*150: R_MIPS_LO16	\.text
 0+0154 <[^>]*> jr	at
 0+0158 <[^>]*> nop
@@ -119,7 +119,7 @@ Disassembly of section \.text:
 0+016c <[^>]*> lw	at,2\(gp\)
 [ 	]*16c: R_MIPS_GOT16	\.text
 0+0170 <[^>]*> nop
-0+0174 <[^>]*> addiu	at,at,1000
+0+0174 <[^>]*> addiu	at,at,992
 [ 	]*174: R_MIPS_LO16	\.text
 0+0178 <[^>]*> jr	at
 0+017c <[^>]*> sw	v0,0\(a0\)
@@ -130,7 +130,7 @@ Disassembly of section \.text:
 0+0190 <[^>]*> lw	at,2\(gp\)
 [ 	]*190: R_MIPS_GOT16	\.text
 0+0194 <[^>]*> nop
-0+0198 <[^>]*> addiu	at,at,1000
+0+0198 <[^>]*> addiu	at,at,992
 [ 	]*198: R_MIPS_LO16	\.text
 0+019c <[^>]*> jr	at
 0+01a0 <[^>]*> sw	v0,0\(a0\)
@@ -145,7 +145,7 @@ Disassembly of section \.text:
 0+01c4 <[^>]*> lw	at,2\(gp\)
 [ 	]*1c4: R_MIPS_GOT16	\.text
 0+01c8 <[^>]*> nop
-0+01cc <[^>]*> addiu	at,at,1000
+0+01cc <[^>]*> addiu	at,at,992
 [ 	]*1cc: R_MIPS_LO16	\.text
 0+01d0 <[^>]*> jr	at
 0+01d4 <[^>]*> nop
@@ -158,154 +158,152 @@ Disassembly of section \.text:
 0+01f0 <[^>]*> lw	at,2\(gp\)
 [ 	]*1f0: R_MIPS_GOT16	\.text
 0+01f4 <[^>]*> nop
-0+01f8 <[^>]*> addiu	at,at,1000
+0+01f8 <[^>]*> addiu	at,at,992
 [ 	]*1f8: R_MIPS_LO16	\.text
 0+01fc <[^>]*> jr	at
 0+0200 <[^>]*> move	a2,a3
-0+0204 <[^>]*> move	v0,a0
-0+0208 <[^>]*> bc1t	00000000 <foo>
-0+020c <[^>]*> nop
-0+0210 <[^>]*> move	v0,a0
-0+0214 <[^>]*> bc1f	0000022c <foo\+0x22c>
+0+0204 <[^>]*> bc1t	00000000 <foo>
+0+0208 <[^>]*> move	v0,a0
+0+020c <[^>]*> bc1f	00000224 <foo\+0x224>
+0+0210 <[^>]*> nop
+0+0214 <[^>]*> lw	at,2\(gp\)
+[ 	]*214: R_MIPS_GOT16	\.text
 0+0218 <[^>]*> nop
-0+021c <[^>]*> lw	at,2\(gp\)
-[ 	]*21c: R_MIPS_GOT16	\.text
-0+0220 <[^>]*> nop
-0+0224 <[^>]*> addiu	at,at,1000
-[ 	]*224: R_MIPS_LO16	\.text
-0+0228 <[^>]*> jr	at
-0+022c <[^>]*> nop
-0+0230 <[^>]*> move	v0,a0
-0+0234 <[^>]*> b	00000000 <foo>
-0+0238 <[^>]*> nop
-0+023c <[^>]*> move	v0,a0
-0+0240 <[^>]*> lw	at,2\(gp\)
-[ 	]*240: R_MIPS_GOT16	\.text
-0+0244 <[^>]*> nop
-0+0248 <[^>]*> addiu	at,at,1000
-[ 	]*248: R_MIPS_LO16	\.text
-0+024c <[^>]*> jr	at
-0+0250 <[^>]*> nop
-0+0254 <[^>]*> move	v0,a0
-0+0258 <[^>]*> b	00000000 <foo>
-0+025c <[^>]*> nop
-0+0260 <[^>]*> move	v0,a0
-0+0264 <[^>]*> lw	at,2\(gp\)
-[ 	]*264: R_MIPS_GOT16	\.text
-0+0268 <[^>]*> nop
-0+026c <[^>]*> addiu	at,at,1000
-[ 	]*26c: R_MIPS_LO16	\.text
-0+0270 <[^>]*> jr	at
-0+0274 <[^>]*> nop
-0+0278 <[^>]*> move	a2,a3
-0+027c <[^>]*> move	v0,a0
-0+0280 <[^>]*> b	00000000 <foo>
-0+0284 <[^>]*> nop
-0+0288 <[^>]*> move	a2,a3
-0+028c <[^>]*> move	v0,a0
-0+0290 <[^>]*> lw	at,2\(gp\)
-[ 	]*290: R_MIPS_GOT16	\.text
-0+0294 <[^>]*> nop
-0+0298 <[^>]*> addiu	at,at,1000
-[ 	]*298: R_MIPS_LO16	\.text
-0+029c <[^>]*> jr	at
+0+021c <[^>]*> addiu	at,at,992
+[ 	]*21c: R_MIPS_LO16	\.text
+0+0220 <[^>]*> jr	at
+0+0224 <[^>]*> move	v0,a0
+0+0228 <[^>]*> move	v0,a0
+0+022c <[^>]*> b	00000000 <foo>
+0+0230 <[^>]*> nop
+0+0234 <[^>]*> move	v0,a0
+0+0238 <[^>]*> lw	at,2\(gp\)
+[ 	]*238: R_MIPS_GOT16	\.text
+0+023c <[^>]*> nop
+0+0240 <[^>]*> addiu	at,at,992
+[ 	]*240: R_MIPS_LO16	\.text
+0+0244 <[^>]*> jr	at
+0+0248 <[^>]*> nop
+0+024c <[^>]*> move	v0,a0
+0+0250 <[^>]*> b	00000000 <foo>
+0+0254 <[^>]*> nop
+0+0258 <[^>]*> move	v0,a0
+0+025c <[^>]*> lw	at,2\(gp\)
+[ 	]*25c: R_MIPS_GOT16	\.text
+0+0260 <[^>]*> nop
+0+0264 <[^>]*> addiu	at,at,992
+[ 	]*264: R_MIPS_LO16	\.text
+0+0268 <[^>]*> jr	at
+0+026c <[^>]*> nop
+0+0270 <[^>]*> move	a2,a3
+0+0274 <[^>]*> move	v0,a0
+0+0278 <[^>]*> b	00000000 <foo>
+0+027c <[^>]*> nop
+0+0280 <[^>]*> move	a2,a3
+0+0284 <[^>]*> move	v0,a0
+0+0288 <[^>]*> lw	at,2\(gp\)
+[ 	]*288: R_MIPS_GOT16	\.text
+0+028c <[^>]*> nop
+0+0290 <[^>]*> addiu	at,at,992
+[ 	]*290: R_MIPS_LO16	\.text
+0+0294 <[^>]*> jr	at
+0+0298 <[^>]*> nop
+0+029c <[^>]*> lw	at,0\(gp\)
+[ 	]*29c: R_MIPS_GOT16	\.text
 0+02a0 <[^>]*> nop
-0+02a4 <[^>]*> lw	at,0\(gp\)
-[ 	]*2a4: R_MIPS_GOT16	\.text
-0+02a8 <[^>]*> nop
-0+02ac <[^>]*> addiu	at,at,692
-[ 	]*2ac: R_MIPS_LO16	\.text
-0+02b0 <[^>]*> sw	v0,0\(at\)
-0+02b4 <[^>]*> b	00000000 <foo>
+0+02a4 <[^>]*> addiu	at,at,684
+[ 	]*2a4: R_MIPS_LO16	\.text
+0+02a8 <[^>]*> sw	v0,0\(at\)
+0+02ac <[^>]*> b	00000000 <foo>
+0+02b0 <[^>]*> nop
+0+02b4 <[^>]*> lw	at,0\(gp\)
+[ 	]*2b4: R_MIPS_GOT16	\.text
 0+02b8 <[^>]*> nop
-0+02bc <[^>]*> lw	at,0\(gp\)
-[ 	]*2bc: R_MIPS_GOT16	\.text
-0+02c0 <[^>]*> nop
-0+02c4 <[^>]*> addiu	at,at,716
-[ 	]*2c4: R_MIPS_LO16	\.text
-0+02c8 <[^>]*> sw	v0,0\(at\)
-0+02cc <[^>]*> lw	at,2\(gp\)
-[ 	]*2cc: R_MIPS_GOT16	\.text
-0+02d0 <[^>]*> nop
-0+02d4 <[^>]*> addiu	at,at,1000
-[ 	]*2d4: R_MIPS_LO16	\.text
-0+02d8 <[^>]*> jr	at
-0+02dc <[^>]*> nop
-0+02e0 <[^>]*> lwc1	\$f0,0\(a0\)
-0+02e4 <[^>]*> b	00000000 <foo>
-0+02e8 <[^>]*> nop
-0+02ec <[^>]*> lwc1	\$f0,0\(a0\)
-0+02f0 <[^>]*> lw	at,2\(gp\)
-[ 	]*2f0: R_MIPS_GOT16	\.text
-0+02f4 <[^>]*> nop
-0+02f8 <[^>]*> addiu	at,at,1000
-[ 	]*2f8: R_MIPS_LO16	\.text
-0+02fc <[^>]*> jr	at
-0+0300 <[^>]*> nop
-0+0304 <[^>]*> cfc1	v0,\$31
-0+0308 <[^>]*> b	00000000 <foo>
-0+030c <[^>]*> nop
-0+0310 <[^>]*> cfc1	v0,\$31
-0+0314 <[^>]*> lw	at,2\(gp\)
-[ 	]*314: R_MIPS_GOT16	\.text
-0+0318 <[^>]*> nop
-0+031c <[^>]*> addiu	at,at,1000
-[ 	]*31c: R_MIPS_LO16	\.text
-0+0320 <[^>]*> jr	at
-0+0324 <[^>]*> nop
-0+0328 <[^>]*> ctc1	v0,\$31
-0+032c <[^>]*> b	00000000 <foo>
-0+0330 <[^>]*> nop
-0+0334 <[^>]*> ctc1	v0,\$31
-0+0338 <[^>]*> lw	at,2\(gp\)
-[ 	]*338: R_MIPS_GOT16	\.text
-0+033c <[^>]*> nop
-0+0340 <[^>]*> addiu	at,at,1000
-[ 	]*340: R_MIPS_LO16	\.text
-0+0344 <[^>]*> jr	at
-0+0348 <[^>]*> nop
-0+034c <[^>]*> mtc1	v0,\$f31
-0+0350 <[^>]*> b	00000000 <foo>
-0+0354 <[^>]*> nop
-0+0358 <[^>]*> mtc1	v0,\$f31
-0+035c <[^>]*> lw	at,2\(gp\)
-[ 	]*35c: R_MIPS_GOT16	\.text
-0+0360 <[^>]*> nop
-0+0364 <[^>]*> addiu	at,at,1000
-[ 	]*364: R_MIPS_LO16	\.text
-0+0368 <[^>]*> jr	at
-0+036c <[^>]*> nop
-0+0370 <[^>]*> mfhi	v0
-0+0374 <[^>]*> b	00000000 <foo>
-0+0378 <[^>]*> nop
-0+037c <[^>]*> mfhi	v0
-0+0380 <[^>]*> lw	at,2\(gp\)
-[ 	]*380: R_MIPS_GOT16	\.text
-0+0384 <[^>]*> nop
-0+0388 <[^>]*> addiu	at,at,1000
-[ 	]*388: R_MIPS_LO16	\.text
-0+038c <[^>]*> jr	at
-0+0390 <[^>]*> nop
-0+0394 <[^>]*> move	v0,a0
-0+0398 <[^>]*> jr	v0
-0+039c <[^>]*> nop
-0+03a0 <[^>]*> jr	a0
-0+03a4 <[^>]*> move	v0,a0
-0+03a8 <[^>]*> move	v0,a0
-0+03ac <[^>]*> jalr	v0
-0+03b0 <[^>]*> nop
-0+03b4 <[^>]*> jalr	a0
-0+03b8 <[^>]*> move	v0,a0
-0+03bc <[^>]*> move	v0,ra
-0+03c0 <[^>]*> jalr	v1
-0+03c4 <[^>]*> nop
-0+03c8 <[^>]*> move	ra,a0
-0+03cc <[^>]*> jalr	a1
-0+03d0 <[^>]*> nop
-0+03d4 <[^>]*> jalr	v0,v1
-0+03d8 <[^>]*> move	ra,a0
-0+03dc <[^>]*> move	v0,ra
-0+03e0 <[^>]*> jalr	v0,v1
-0+03e4 <[^>]*> nop
+0+02bc <[^>]*> addiu	at,at,708
+[ 	]*2bc: R_MIPS_LO16	\.text
+0+02c0 <[^>]*> sw	v0,0\(at\)
+0+02c4 <[^>]*> lw	at,2\(gp\)
+[ 	]*2c4: R_MIPS_GOT16	\.text
+0+02c8 <[^>]*> nop
+0+02cc <[^>]*> addiu	at,at,992
+[ 	]*2cc: R_MIPS_LO16	\.text
+0+02d0 <[^>]*> jr	at
+0+02d4 <[^>]*> nop
+0+02d8 <[^>]*> lwc1	\$f0,0\(a0\)
+0+02dc <[^>]*> b	00000000 <foo>
+0+02e0 <[^>]*> nop
+0+02e4 <[^>]*> lwc1	\$f0,0\(a0\)
+0+02e8 <[^>]*> lw	at,2\(gp\)
+[ 	]*2e8: R_MIPS_GOT16	\.text
+0+02ec <[^>]*> nop
+0+02f0 <[^>]*> addiu	at,at,992
+[ 	]*2f0: R_MIPS_LO16	\.text
+0+02f4 <[^>]*> jr	at
+0+02f8 <[^>]*> nop
+0+02fc <[^>]*> cfc1	v0,\$31
+0+0300 <[^>]*> b	00000000 <foo>
+0+0304 <[^>]*> nop
+0+0308 <[^>]*> cfc1	v0,\$31
+0+030c <[^>]*> lw	at,2\(gp\)
+[ 	]*30c: R_MIPS_GOT16	\.text
+0+0310 <[^>]*> nop
+0+0314 <[^>]*> addiu	at,at,992
+[ 	]*314: R_MIPS_LO16	\.text
+0+0318 <[^>]*> jr	at
+0+031c <[^>]*> nop
+0+0320 <[^>]*> ctc1	v0,\$31
+0+0324 <[^>]*> b	00000000 <foo>
+0+0328 <[^>]*> nop
+0+032c <[^>]*> ctc1	v0,\$31
+0+0330 <[^>]*> lw	at,2\(gp\)
+[ 	]*330: R_MIPS_GOT16	\.text
+0+0334 <[^>]*> nop
+0+0338 <[^>]*> addiu	at,at,992
+[ 	]*338: R_MIPS_LO16	\.text
+0+033c <[^>]*> jr	at
+0+0340 <[^>]*> nop
+0+0344 <[^>]*> mtc1	v0,\$f31
+0+0348 <[^>]*> b	00000000 <foo>
+0+034c <[^>]*> nop
+0+0350 <[^>]*> mtc1	v0,\$f31
+0+0354 <[^>]*> lw	at,2\(gp\)
+[ 	]*354: R_MIPS_GOT16	\.text
+0+0358 <[^>]*> nop
+0+035c <[^>]*> addiu	at,at,992
+[ 	]*35c: R_MIPS_LO16	\.text
+0+0360 <[^>]*> jr	at
+0+0364 <[^>]*> nop
+0+0368 <[^>]*> mfhi	v0
+0+036c <[^>]*> b	00000000 <foo>
+0+0370 <[^>]*> nop
+0+0374 <[^>]*> mfhi	v0
+0+0378 <[^>]*> lw	at,2\(gp\)
+[ 	]*378: R_MIPS_GOT16	\.text
+0+037c <[^>]*> nop
+0+0380 <[^>]*> addiu	at,at,992
+[ 	]*380: R_MIPS_LO16	\.text
+0+0384 <[^>]*> jr	at
+0+0388 <[^>]*> nop
+0+038c <[^>]*> move	v0,a0
+0+0390 <[^>]*> jr	v0
+0+0394 <[^>]*> nop
+0+0398 <[^>]*> jr	a0
+0+039c <[^>]*> move	v0,a0
+0+03a0 <[^>]*> move	v0,a0
+0+03a4 <[^>]*> jalr	v0
+0+03a8 <[^>]*> nop
+0+03ac <[^>]*> jalr	a0
+0+03b0 <[^>]*> move	v0,a0
+0+03b4 <[^>]*> move	v0,ra
+0+03b8 <[^>]*> jalr	v1
+0+03bc <[^>]*> nop
+0+03c0 <[^>]*> move	ra,a0
+0+03c4 <[^>]*> jalr	a1
+0+03c8 <[^>]*> nop
+0+03cc <[^>]*> jalr	v0,v1
+0+03d0 <[^>]*> move	ra,a0
+0+03d4 <[^>]*> move	v0,ra
+0+03d8 <[^>]*> jalr	v0,v1
+0+03dc <[^>]*> nop
 	\.\.\.
 	\.\.\.
diff -urpN gas.10/testsuite/gas/mips/relax-swap1-mips2.d gas/testsuite/gas/mips/relax-swap1-mips2.d
--- gas.10/testsuite/gas/mips/relax-swap1-mips2.d	2005-02-28 09:24:25.000000000 +0000
+++ gas/testsuite/gas/mips/relax-swap1-mips2.d	2005-03-08 12:48:34.000000000 +0000
@@ -11,7 +11,7 @@ Disassembly of section \.text:
 0+0004 <[^>]*> move	v0,a0
 0+0008 <[^>]*> lw	at,2\(gp\)
 [ 	]*8: R_MIPS_GOT16	\.text
-0+000c <[^>]*> addiu	at,at,868
+0+000c <[^>]*> addiu	at,at,860
 [ 	]*c: R_MIPS_LO16	\.text
 0+0010 <[^>]*> jr	at
 0+0014 <[^>]*> move	v0,a0
@@ -19,7 +19,7 @@ Disassembly of section \.text:
 0+001c <[^>]*> lw	v0,0\(a0\)
 0+0020 <[^>]*> lw	at,2\(gp\)
 [ 	]*20: R_MIPS_GOT16	\.text
-0+0024 <[^>]*> addiu	at,at,868
+0+0024 <[^>]*> addiu	at,at,860
 [ 	]*24: R_MIPS_LO16	\.text
 0+0028 <[^>]*> jr	at
 0+002c <[^>]*> lw	v0,0\(a0\)
@@ -27,7 +27,7 @@ Disassembly of section \.text:
 0+0034 <[^>]*> sw	v0,0\(a0\)
 0+0038 <[^>]*> lw	at,2\(gp\)
 [ 	]*38: R_MIPS_GOT16	\.text
-0+003c <[^>]*> addiu	at,at,868
+0+003c <[^>]*> addiu	at,at,860
 [ 	]*3c: R_MIPS_LO16	\.text
 0+0040 <[^>]*> jr	at
 0+0044 <[^>]*> sw	v0,0\(a0\)
@@ -39,7 +39,7 @@ Disassembly of section \.text:
 0+005c <[^>]*> nop
 0+0060 <[^>]*> lw	at,2\(gp\)
 [ 	]*60: R_MIPS_GOT16	\.text
-0+0064 <[^>]*> addiu	at,at,868
+0+0064 <[^>]*> addiu	at,at,860
 [ 	]*64: R_MIPS_LO16	\.text
 0+0068 <[^>]*> jr	at
 0+006c <[^>]*> nop
@@ -49,7 +49,7 @@ Disassembly of section \.text:
 0+007c <[^>]*> nop
 0+0080 <[^>]*> lw	at,2\(gp\)
 [ 	]*80: R_MIPS_GOT16	\.text
-0+0084 <[^>]*> addiu	at,at,868
+0+0084 <[^>]*> addiu	at,at,860
 [ 	]*84: R_MIPS_LO16	\.text
 0+0088 <[^>]*> jr	at
 0+008c <[^>]*> move	v0,a0
@@ -61,7 +61,7 @@ Disassembly of section \.text:
 0+00a4 <[^>]*> nop
 0+00a8 <[^>]*> lw	at,2\(gp\)
 [ 	]*a8: R_MIPS_GOT16	\.text
-0+00ac <[^>]*> addiu	at,at,868
+0+00ac <[^>]*> addiu	at,at,860
 [ 	]*ac: R_MIPS_LO16	\.text
 0+00b0 <[^>]*> jr	at
 0+00b4 <[^>]*> nop
@@ -71,7 +71,7 @@ Disassembly of section \.text:
 0+00c4 <[^>]*> nop
 0+00c8 <[^>]*> lw	at,2\(gp\)
 [ 	]*c8: R_MIPS_GOT16	\.text
-0+00cc <[^>]*> addiu	at,at,868
+0+00cc <[^>]*> addiu	at,at,860
 [ 	]*cc: R_MIPS_LO16	\.text
 0+00d0 <[^>]*> jr	at
 0+00d4 <[^>]*> addiu	v0,a0,1
@@ -83,7 +83,7 @@ Disassembly of section \.text:
 0+00ec <[^>]*> nop
 0+00f0 <[^>]*> lw	at,2\(gp\)
 [ 	]*f0: R_MIPS_GOT16	\.text
-0+00f4 <[^>]*> addiu	at,at,868
+0+00f4 <[^>]*> addiu	at,at,860
 [ 	]*f4: R_MIPS_LO16	\.text
 0+00f8 <[^>]*> jr	at
 0+00fc <[^>]*> nop
@@ -93,7 +93,7 @@ Disassembly of section \.text:
 0+010c <[^>]*> nop
 0+0110 <[^>]*> lw	at,2\(gp\)
 [ 	]*110: R_MIPS_GOT16	\.text
-0+0114 <[^>]*> addiu	at,at,868
+0+0114 <[^>]*> addiu	at,at,860
 [ 	]*114: R_MIPS_LO16	\.text
 0+0118 <[^>]*> jr	at
 0+011c <[^>]*> lw	v0,0\(a0\)
@@ -103,7 +103,7 @@ Disassembly of section \.text:
 0+012c <[^>]*> nop
 0+0130 <[^>]*> lw	at,2\(gp\)
 [ 	]*130: R_MIPS_GOT16	\.text
-0+0134 <[^>]*> addiu	at,at,868
+0+0134 <[^>]*> addiu	at,at,860
 [ 	]*134: R_MIPS_LO16	\.text
 0+0138 <[^>]*> jr	at
 0+013c <[^>]*> sw	v0,0\(a0\)
@@ -113,7 +113,7 @@ Disassembly of section \.text:
 0+014c <[^>]*> nop
 0+0150 <[^>]*> lw	at,2\(gp\)
 [ 	]*150: R_MIPS_GOT16	\.text
-0+0154 <[^>]*> addiu	at,at,868
+0+0154 <[^>]*> addiu	at,at,860
 [ 	]*154: R_MIPS_LO16	\.text
 0+0158 <[^>]*> jr	at
 0+015c <[^>]*> sw	v0,0\(a0\)
@@ -127,7 +127,7 @@ Disassembly of section \.text:
 0+017c <[^>]*> nop
 0+0180 <[^>]*> lw	at,2\(gp\)
 [ 	]*180: R_MIPS_GOT16	\.text
-0+0184 <[^>]*> addiu	at,at,868
+0+0184 <[^>]*> addiu	at,at,860
 [ 	]*184: R_MIPS_LO16	\.text
 0+0188 <[^>]*> jr	at
 0+018c <[^>]*> nop
@@ -139,140 +139,138 @@ Disassembly of section \.text:
 0+01a4 <[^>]*> nop
 0+01a8 <[^>]*> lw	at,2\(gp\)
 [ 	]*1a8: R_MIPS_GOT16	\.text
-0+01ac <[^>]*> addiu	at,at,868
+0+01ac <[^>]*> addiu	at,at,860
 [ 	]*1ac: R_MIPS_LO16	\.text
 0+01b0 <[^>]*> jr	at
 0+01b4 <[^>]*> move	a2,a3
-0+01b8 <[^>]*> move	v0,a0
-0+01bc <[^>]*> bc1t	00000000 <foo>
-0+01c0 <[^>]*> nop
-0+01c4 <[^>]*> move	v0,a0
-0+01c8 <[^>]*> bc1f	000001dc <foo\+0x1dc>
-0+01cc <[^>]*> nop
-0+01d0 <[^>]*> lw	at,2\(gp\)
-[ 	]*1d0: R_MIPS_GOT16	\.text
-0+01d4 <[^>]*> addiu	at,at,868
-[ 	]*1d4: R_MIPS_LO16	\.text
-0+01d8 <[^>]*> jr	at
-0+01dc <[^>]*> nop
-0+01e0 <[^>]*> move	v0,a0
-0+01e4 <[^>]*> b	00000000 <foo>
-0+01e8 <[^>]*> nop
-0+01ec <[^>]*> move	v0,a0
-0+01f0 <[^>]*> lw	at,2\(gp\)
-[ 	]*1f0: R_MIPS_GOT16	\.text
-0+01f4 <[^>]*> addiu	at,at,868
-[ 	]*1f4: R_MIPS_LO16	\.text
-0+01f8 <[^>]*> jr	at
-0+01fc <[^>]*> nop
-0+0200 <[^>]*> move	v0,a0
-0+0204 <[^>]*> b	00000000 <foo>
-0+0208 <[^>]*> nop
-0+020c <[^>]*> move	v0,a0
-0+0210 <[^>]*> lw	at,2\(gp\)
-[ 	]*210: R_MIPS_GOT16	\.text
-0+0214 <[^>]*> addiu	at,at,868
-[ 	]*214: R_MIPS_LO16	\.text
-0+0218 <[^>]*> jr	at
-0+021c <[^>]*> nop
-0+0220 <[^>]*> move	a2,a3
-0+0224 <[^>]*> move	v0,a0
-0+0228 <[^>]*> b	00000000 <foo>
-0+022c <[^>]*> nop
-0+0230 <[^>]*> move	a2,a3
-0+0234 <[^>]*> move	v0,a0
-0+0238 <[^>]*> lw	at,2\(gp\)
-[ 	]*238: R_MIPS_GOT16	\.text
-0+023c <[^>]*> addiu	at,at,868
-[ 	]*23c: R_MIPS_LO16	\.text
-0+0240 <[^>]*> jr	at
-0+0244 <[^>]*> nop
-0+0248 <[^>]*> lw	at,0\(gp\)
-[ 	]*248: R_MIPS_GOT16	\.text
-0+024c <[^>]*> addiu	at,at,596
-[ 	]*24c: R_MIPS_LO16	\.text
-0+0250 <[^>]*> sw	v0,0\(at\)
-0+0254 <[^>]*> b	00000000 <foo>
-0+0258 <[^>]*> nop
-0+025c <[^>]*> lw	at,0\(gp\)
-[ 	]*25c: R_MIPS_GOT16	\.text
-0+0260 <[^>]*> addiu	at,at,616
-[ 	]*260: R_MIPS_LO16	\.text
-0+0264 <[^>]*> sw	v0,0\(at\)
-0+0268 <[^>]*> lw	at,2\(gp\)
-[ 	]*268: R_MIPS_GOT16	\.text
-0+026c <[^>]*> addiu	at,at,868
-[ 	]*26c: R_MIPS_LO16	\.text
-0+0270 <[^>]*> jr	at
-0+0274 <[^>]*> nop
-0+0278 <[^>]*> b	00000000 <foo>
-0+027c <[^>]*> lwc1	\$f0,0\(a0\)
-0+0280 <[^>]*> lw	at,2\(gp\)
-[ 	]*280: R_MIPS_GOT16	\.text
-0+0284 <[^>]*> addiu	at,at,868
-[ 	]*284: R_MIPS_LO16	\.text
-0+0288 <[^>]*> jr	at
-0+028c <[^>]*> lwc1	\$f0,0\(a0\)
-0+0290 <[^>]*> cfc1	v0,\$31
-0+0294 <[^>]*> b	00000000 <foo>
-0+0298 <[^>]*> nop
-0+029c <[^>]*> cfc1	v0,\$31
-0+02a0 <[^>]*> lw	at,2\(gp\)
-[ 	]*2a0: R_MIPS_GOT16	\.text
-0+02a4 <[^>]*> addiu	at,at,868
-[ 	]*2a4: R_MIPS_LO16	\.text
-0+02a8 <[^>]*> jr	at
-0+02ac <[^>]*> nop
-0+02b0 <[^>]*> ctc1	v0,\$31
-0+02b4 <[^>]*> b	00000000 <foo>
-0+02b8 <[^>]*> nop
-0+02bc <[^>]*> ctc1	v0,\$31
-0+02c0 <[^>]*> lw	at,2\(gp\)
-[ 	]*2c0: R_MIPS_GOT16	\.text
-0+02c4 <[^>]*> addiu	at,at,868
-[ 	]*2c4: R_MIPS_LO16	\.text
-0+02c8 <[^>]*> jr	at
-0+02cc <[^>]*> nop
-0+02d0 <[^>]*> mtc1	v0,\$f31
-0+02d4 <[^>]*> b	00000000 <foo>
-0+02d8 <[^>]*> nop
-0+02dc <[^>]*> mtc1	v0,\$f31
-0+02e0 <[^>]*> lw	at,2\(gp\)
-[ 	]*2e0: R_MIPS_GOT16	\.text
-0+02e4 <[^>]*> addiu	at,at,868
-[ 	]*2e4: R_MIPS_LO16	\.text
-0+02e8 <[^>]*> jr	at
-0+02ec <[^>]*> nop
-0+02f0 <[^>]*> mfhi	v0
-0+02f4 <[^>]*> b	00000000 <foo>
-0+02f8 <[^>]*> nop
-0+02fc <[^>]*> mfhi	v0
-0+0300 <[^>]*> lw	at,2\(gp\)
-[ 	]*300: R_MIPS_GOT16	\.text
-0+0304 <[^>]*> addiu	at,at,868
-[ 	]*304: R_MIPS_LO16	\.text
-0+0308 <[^>]*> jr	at
-0+030c <[^>]*> nop
-0+0310 <[^>]*> move	v0,a0
-0+0314 <[^>]*> jr	v0
-0+0318 <[^>]*> nop
-0+031c <[^>]*> jr	a0
-0+0320 <[^>]*> move	v0,a0
-0+0324 <[^>]*> move	v0,a0
-0+0328 <[^>]*> jalr	v0
-0+032c <[^>]*> nop
-0+0330 <[^>]*> jalr	a0
-0+0334 <[^>]*> move	v0,a0
-0+0338 <[^>]*> move	v0,ra
-0+033c <[^>]*> jalr	v1
-0+0340 <[^>]*> nop
-0+0344 <[^>]*> move	ra,a0
-0+0348 <[^>]*> jalr	a1
-0+034c <[^>]*> nop
-0+0350 <[^>]*> jalr	v0,v1
-0+0354 <[^>]*> move	ra,a0
-0+0358 <[^>]*> move	v0,ra
-0+035c <[^>]*> jalr	v0,v1
-0+0360 <[^>]*> nop
+0+01b8 <[^>]*> bc1t	00000000 <foo>
+0+01bc <[^>]*> move	v0,a0
+0+01c0 <[^>]*> bc1f	000001d4 <foo\+0x1d4>
+0+01c4 <[^>]*> nop
+0+01c8 <[^>]*> lw	at,2\(gp\)
+[ 	]*1c8: R_MIPS_GOT16	\.text
+0+01cc <[^>]*> addiu	at,at,860
+[ 	]*1cc: R_MIPS_LO16	\.text
+0+01d0 <[^>]*> jr	at
+0+01d4 <[^>]*> move	v0,a0
+0+01d8 <[^>]*> move	v0,a0
+0+01dc <[^>]*> b	00000000 <foo>
+0+01e0 <[^>]*> nop
+0+01e4 <[^>]*> move	v0,a0
+0+01e8 <[^>]*> lw	at,2\(gp\)
+[ 	]*1e8: R_MIPS_GOT16	\.text
+0+01ec <[^>]*> addiu	at,at,860
+[ 	]*1ec: R_MIPS_LO16	\.text
+0+01f0 <[^>]*> jr	at
+0+01f4 <[^>]*> nop
+0+01f8 <[^>]*> move	v0,a0
+0+01fc <[^>]*> b	00000000 <foo>
+0+0200 <[^>]*> nop
+0+0204 <[^>]*> move	v0,a0
+0+0208 <[^>]*> lw	at,2\(gp\)
+[ 	]*208: R_MIPS_GOT16	\.text
+0+020c <[^>]*> addiu	at,at,860
+[ 	]*20c: R_MIPS_LO16	\.text
+0+0210 <[^>]*> jr	at
+0+0214 <[^>]*> nop
+0+0218 <[^>]*> move	a2,a3
+0+021c <[^>]*> move	v0,a0
+0+0220 <[^>]*> b	00000000 <foo>
+0+0224 <[^>]*> nop
+0+0228 <[^>]*> move	a2,a3
+0+022c <[^>]*> move	v0,a0
+0+0230 <[^>]*> lw	at,2\(gp\)
+[ 	]*230: R_MIPS_GOT16	\.text
+0+0234 <[^>]*> addiu	at,at,860
+[ 	]*234: R_MIPS_LO16	\.text
+0+0238 <[^>]*> jr	at
+0+023c <[^>]*> nop
+0+0240 <[^>]*> lw	at,0\(gp\)
+[ 	]*240: R_MIPS_GOT16	\.text
+0+0244 <[^>]*> addiu	at,at,588
+[ 	]*244: R_MIPS_LO16	\.text
+0+0248 <[^>]*> sw	v0,0\(at\)
+0+024c <[^>]*> b	00000000 <foo>
+0+0250 <[^>]*> nop
+0+0254 <[^>]*> lw	at,0\(gp\)
+[ 	]*254: R_MIPS_GOT16	\.text
+0+0258 <[^>]*> addiu	at,at,608
+[ 	]*258: R_MIPS_LO16	\.text
+0+025c <[^>]*> sw	v0,0\(at\)
+0+0260 <[^>]*> lw	at,2\(gp\)
+[ 	]*260: R_MIPS_GOT16	\.text
+0+0264 <[^>]*> addiu	at,at,860
+[ 	]*264: R_MIPS_LO16	\.text
+0+0268 <[^>]*> jr	at
+0+026c <[^>]*> nop
+0+0270 <[^>]*> b	00000000 <foo>
+0+0274 <[^>]*> lwc1	\$f0,0\(a0\)
+0+0278 <[^>]*> lw	at,2\(gp\)
+[ 	]*278: R_MIPS_GOT16	\.text
+0+027c <[^>]*> addiu	at,at,860
+[ 	]*27c: R_MIPS_LO16	\.text
+0+0280 <[^>]*> jr	at
+0+0284 <[^>]*> lwc1	\$f0,0\(a0\)
+0+0288 <[^>]*> cfc1	v0,\$31
+0+028c <[^>]*> b	00000000 <foo>
+0+0290 <[^>]*> nop
+0+0294 <[^>]*> cfc1	v0,\$31
+0+0298 <[^>]*> lw	at,2\(gp\)
+[ 	]*298: R_MIPS_GOT16	\.text
+0+029c <[^>]*> addiu	at,at,860
+[ 	]*29c: R_MIPS_LO16	\.text
+0+02a0 <[^>]*> jr	at
+0+02a4 <[^>]*> nop
+0+02a8 <[^>]*> ctc1	v0,\$31
+0+02ac <[^>]*> b	00000000 <foo>
+0+02b0 <[^>]*> nop
+0+02b4 <[^>]*> ctc1	v0,\$31
+0+02b8 <[^>]*> lw	at,2\(gp\)
+[ 	]*2b8: R_MIPS_GOT16	\.text
+0+02bc <[^>]*> addiu	at,at,860
+[ 	]*2bc: R_MIPS_LO16	\.text
+0+02c0 <[^>]*> jr	at
+0+02c4 <[^>]*> nop
+0+02c8 <[^>]*> mtc1	v0,\$f31
+0+02cc <[^>]*> b	00000000 <foo>
+0+02d0 <[^>]*> nop
+0+02d4 <[^>]*> mtc1	v0,\$f31
+0+02d8 <[^>]*> lw	at,2\(gp\)
+[ 	]*2d8: R_MIPS_GOT16	\.text
+0+02dc <[^>]*> addiu	at,at,860
+[ 	]*2dc: R_MIPS_LO16	\.text
+0+02e0 <[^>]*> jr	at
+0+02e4 <[^>]*> nop
+0+02e8 <[^>]*> mfhi	v0
+0+02ec <[^>]*> b	00000000 <foo>
+0+02f0 <[^>]*> nop
+0+02f4 <[^>]*> mfhi	v0
+0+02f8 <[^>]*> lw	at,2\(gp\)
+[ 	]*2f8: R_MIPS_GOT16	\.text
+0+02fc <[^>]*> addiu	at,at,860
+[ 	]*2fc: R_MIPS_LO16	\.text
+0+0300 <[^>]*> jr	at
+0+0304 <[^>]*> nop
+0+0308 <[^>]*> move	v0,a0
+0+030c <[^>]*> jr	v0
+0+0310 <[^>]*> nop
+0+0314 <[^>]*> jr	a0
+0+0318 <[^>]*> move	v0,a0
+0+031c <[^>]*> move	v0,a0
+0+0320 <[^>]*> jalr	v0
+0+0324 <[^>]*> nop
+0+0328 <[^>]*> jalr	a0
+0+032c <[^>]*> move	v0,a0
+0+0330 <[^>]*> move	v0,ra
+0+0334 <[^>]*> jalr	v1
+0+0338 <[^>]*> nop
+0+033c <[^>]*> move	ra,a0
+0+0340 <[^>]*> jalr	a1
+0+0344 <[^>]*> nop
+0+0348 <[^>]*> jalr	v0,v1
+0+034c <[^>]*> move	ra,a0
+0+0350 <[^>]*> move	v0,ra
+0+0354 <[^>]*> jalr	v0,v1
+0+0358 <[^>]*> nop
 	\.\.\.
 	\.\.\.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11]
  2005-03-08 15:12                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Richard Sandiford
@ 2005-03-08 15:16                   ` Richard Sandiford
  2005-03-08 19:45                     ` Eric Christopher
  2005-03-08 19:43                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Eric Christopher
  1 sibling, 1 reply; 23+ messages in thread
From: Richard Sandiford @ 2005-03-08 15:16 UTC (permalink / raw)
  To: binutils

Finally, the -mfix-vr4130 patch itself.  The main question with this
patch was whether gas should insert a sequence of normal nops or
whether it should insert instructions that read the destination of
the problematic mflo or mfhi.  I went for the former because:

  (1) There are some complex performance trade-offs involved.  Reading
      the mflo or mfhi register would often not be a win performance-wise.

  (2) Perhaps surprisingly, the problematic sequence seems to occur very
      rarely in real code.  We need very few nops in the tests I've run.

  (3) The gcc implementation of -mfix-vr4130 will avoid using mfhi and
      mflo altogether for non-MIPS16 -march=vr4120 and -march=vr4130 code.

Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?

Richard


	* config/tc-mips.c (MAX_VR4130_NOPS, MAX_DELAY_NOPS): New macros.
	(MAX_NOPS): Bump to 4.
	(mips_fix_vr4130): New variable.
	(nops_for_vr4130): New function.
	(nops_for_insn): Use MAX_DELAY_NOPS rather than MAX_NOPS.  Use
	nops_for_vr4130 if working around VR4130 errata.
	(OPTION_FIX_VR4130, OPTION_NO_FIX_VR4130): New macros.
	(md_longopts): Add -mfix-vr4130 and -mno-fix-vr4130.
	(md_parse_option): Handle them.
	(md_show_usage): Print them.
	* doc/c-mips.texi: Document -mfix-vr4130 and -mno-fix-vr4130.

testsuite/
	* gas/mips/vr4130.[sd]: New test.
	* gas/mips/mips.exp: Run it.

diff -crpN gas.11/config/tc-mips.c gas/config/tc-mips.c
*** gas.11/config/tc-mips.c	2005-03-08 12:48:34.000000000 +0000
--- gas/config/tc-mips.c	2005-03-08 13:27:29.598842201 +0000
*************** static int mips_optimize = 2;
*** 557,565 ****
     equivalent to seeing no -g option at all.  */
  static int mips_debug = 0;
  
! /* The maximum number of NOPs needed to satisfy a hardware hazard
!    or processor errata.  */
! #define MAX_NOPS 2
  
  /* A list of previous instructions, with index 0 being the most recent.
     We need to look back MAX_NOPS instructions when filling delay slots
--- 557,570 ----
     equivalent to seeing no -g option at all.  */
  static int mips_debug = 0;
  
! /* The maximum number of NOPs needed to avoid the VR4130 mflo/mfhi errata.  */
! #define MAX_VR4130_NOPS 4
! 
! /* The maximum number of NOPs needed to fill delay slots.  */
! #define MAX_DELAY_NOPS 2
! 
! /* The maximum number of NOPs needed for any purpose.  */
! #define MAX_NOPS 4
  
  /* A list of previous instructions, with index 0 being the most recent.
     We need to look back MAX_NOPS instructions when filling delay slots
*************** static unsigned int vr4120_conflicts[NUM
*** 659,664 ****
--- 664,672 ----
  /* 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
*************** nops_between (const struct mips_cl_insn 
*** 2011,2016 ****
--- 2019,2066 ----
    return 0;
  }
  
+ /* Return the number of nops that would be needed to work around the
+    VR4130 mflo/mfhi errata if instruction INSN immediately followed
+    history[FIRST].  */
+ 
+ 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,
*************** nops_for_insn (const struct mips_cl_insn
*** 2023,2035 ****
    int i, nops, tmp_nops;
  
    nops = 0;
!   for (i = 0; i < MAX_NOPS; i++)
      if (!history[i].noreorder_p)
        {
  	tmp_nops = nops_between (history + i, insn) - i;
  	if (tmp_nops > nops)
  	  nops = tmp_nops;
        }
    return nops;
  }
  
--- 2073,2093 ----
    int i, nops, tmp_nops;
  
    nops = 0;
!   for (i = 0; i < MAX_DELAY_NOPS; i++)
      if (!history[i].noreorder_p)
        {
  	tmp_nops = nops_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;
  }
  
*************** struct option md_longopts[] =
*** 9966,9974 ****
  #define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
    {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
    {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
  
    /* Miscellaneous options.  */
! #define OPTION_MISC_BASE (OPTION_FIX_BASE + 4)
  #define OPTION_TRAP (OPTION_MISC_BASE + 0)
    {"trap", no_argument, NULL, OPTION_TRAP},
    {"no-break", no_argument, NULL, OPTION_TRAP},
--- 10024,10036 ----
  #define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
    {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
    {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
+ #define OPTION_FIX_VR4130 (OPTION_FIX_BASE + 4)
+ #define OPTION_NO_FIX_VR4130 (OPTION_FIX_BASE + 5)
+   {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
+   {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
  
    /* Miscellaneous options.  */
! #define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
  #define OPTION_TRAP (OPTION_MISC_BASE + 0)
    {"trap", no_argument, NULL, OPTION_TRAP},
    {"no-break", no_argument, NULL, OPTION_TRAP},
*************** md_parse_option (int c, char *arg)
*** 10211,10216 ****
--- 10273,10286 ----
        mips_fix_vr4120 = 0;
        break;
  
+     case OPTION_FIX_VR4130:
+       mips_fix_vr4130 = 1;
+       break;
+ 
+     case OPTION_NO_FIX_VR4130:
+       mips_fix_vr4130 = 0;
+       break;
+ 
      case OPTION_RELAX_BRANCH:
        mips_relax_branch = 1;
        break;
*************** MIPS options:\n\
*** 13886,13891 ****
--- 13956,13962 ----
  -no-mips16		do not generate mips16 instructions\n"));
    fprintf (stream, _("\
  -mfix-vr4120		work around certain VR4120 errata\n\
+ -mfix-vr4130		work around VR4130 mflo/mfhi errata\n\
  -mgp32			use 32-bit GPRs, regardless of the chosen ISA\n\
  -mfp32			use 32-bit FPRs, regardless of the chosen ISA\n\
  -mno-shared		optimize output for executables\n\
diff -crpN gas.11/doc/c-mips.texi gas/doc/c-mips.texi
*** gas.11/doc/c-mips.texi	2005-03-08 08:59:35.000000000 +0000
--- gas/doc/c-mips.texi	2005-03-08 13:27:29.000000000 +0000
*************** Insert nops to work around certain VR412
*** 129,134 ****
--- 129,138 ----
  intended to be used on GCC-generated code: it is not designed to catch
  all problems in hand-written assembler code.
  
+ @item -mfix-vr4130
+ @itemx -no-mfix-vr4130
+ Insert nops to work around the VR4130 @samp{mflo}/@samp{mfhi} errata.
+ 
  @item -m4010
  @itemx -no-m4010
  Generate code for the LSI @sc{r4010} chip.  This tells the assembler to
diff -crpN gas.11/testsuite/gas/mips/mips.exp gas/testsuite/gas/mips/mips.exp
*** gas.11/testsuite/gas/mips/mips.exp	2005-03-08 13:09:33.000000000 +0000
--- gas/testsuite/gas/mips/mips.exp	2005-03-08 13:27:29.625838218 +0000
*************** if { [istarget mips*-*-*] } then {
*** 544,549 ****
--- 544,550 ----
      run_dump_test "vr4111"
      run_dump_test "vr4120"
      run_dump_test "vr4120-2"
+     run_dump_test "vr4130"
      run_dump_test "vr5400"
      run_dump_test "vr5500"
      run_dump_test "rm7000"
diff -crpN gas.11/testsuite/gas/mips/vr4130.d gas/testsuite/gas/mips/vr4130.d
*** gas.11/testsuite/gas/mips/vr4130.d	1970-01-01 01:00:00.000000000 +0100
--- gas/testsuite/gas/mips/vr4130.d	2005-03-08 13:27:29.628837776 +0000
***************
*** 0 ****
--- 1,705 ----
+ #as: -mfix-vr4130 -march=vr4130 -mabi=o64
+ #objdump: -dz
+ #name: MIPS VR4130 workarounds
+ 
+ .*file format.*
+ 
+ Disassembly.*
+ 
+ .* <foo>:
+ #
+ # PART A
+ #
+ .*	mfhi	.*
+ .*	mult	.*
+ #
+ .*	mflo	.*
+ .*	mult	.*
+ #
+ # PART B
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART C
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART D
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ # PART E
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	bnez	.*
+ .*	nop
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	bnez	.*
+ .*	nop
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ .*	nop
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ .*	nop
+ #
+ # PART F
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	bnez	.*
+ .*	nop
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ .*	nop
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ .*	addiu	.*
+ #
+ # PART G
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART H
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART I
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	multu	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmult	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmultu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	div	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	divu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	ddiv	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	ddivu	.*
+ #
+ # PART J
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	macc	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	macchi	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	macchis	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	macchiu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	macchius	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	maccs	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	maccu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	maccus	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmacc	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmacchi	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmacchis	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmacchiu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmacchius	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmaccs	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmaccu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmaccus	.*
+ #
+ # PART K
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	mtlo	.*
+ #
+ .*	mflo	.*
+ .*	mthi	.*
+ #
+ .*	mfhi	.*
+ .*	mtlo	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	mthi	.*
+ 
+ .* <bar>:
+ #
+ # PART A
+ #
+ .*	mfhi	.*
+ .*	mult	.*
+ #
+ .*	mflo	.*
+ .*	mult	.*
+ #
+ # PART B
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART C
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART D
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ # PART E
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	bnez	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	bnez	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	bnez	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ #
+ # PART F
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	bnez	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	bnez	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	bnez	.*
+ #
+ # PART G
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART H
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	nop
+ .*	nop
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ .*	mfhi	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	addiu	.*
+ .*	mult	.*
+ #
+ # PART I
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	mult	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	multu	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmult	.*
+ #
+ .*	mflo	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	dmultu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	div	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	divu	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	ddiv	.*
+ #
+ .*	mfhi	.*
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	nop
+ .*	ddivu	.*
+ #pass
diff -crpN gas.11/testsuite/gas/mips/vr4130.s gas/testsuite/gas/mips/vr4130.s
*** gas.11/testsuite/gas/mips/vr4130.s	1970-01-01 01:00:00.000000000 +0100
--- gas/testsuite/gas/mips/vr4130.s	2005-03-08 13:27:29.630837481 +0000
***************
*** 0 ****
--- 1,305 ----
+ 	.macro	check2 insn
+ 	mflo	$2
+ 	\insn	$3,$3
+ 	.endm
+ 
+ 	.macro	check3 insn
+ 	mfhi	$2
+ 	\insn	$0,$3,$3
+ 	.endm
+ 
+ 	.macro	main func
+ 
+ 	.ent	\func
+ 	.type	\func,@function
+ \func:
+ 
+ 	# PART A
+ 	#
+ 	# Check that mfhis and mflos in .set noreorder blocks are not
+ 	# considered.
+ 
+ 	.set	noreorder
+ 	mfhi	$2
+ 	.set	reorder
+ 	mult	$3,$3
+ 
+ 	.set	noreorder
+ 	mflo	$2
+ 	.set	reorder
+ 	mult	$3,$3
+ 
+ 	# PART B
+ 	#
+ 	# Check for simple instances.
+ 
+ 	mfhi	$2
+ 	mult	$3,$3	# 4 nops
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	mult	$4,$4	# 3 nops
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	mult	$5,$5	# 2 nops
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	mult	$6,$6	# 1 nop
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	addiu	$6,1
+ 	mult	$7,$7	# 0 nops
+ 
+ 	# PART C
+ 	#
+ 	# Check that no nops are inserted after the result has been read.
+ 
+ 	mfhi	$2
+ 	addiu	$2,1
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	mult	$5,$5
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$2,1
+ 	addiu	$4,1
+ 	mult	$5,$5
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$2,1
+ 	mult	$5,$5
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	mult	$2,$2
+ 
+ 	# PART D
+ 	#
+ 	# Check that we still insert the usual interlocking nops in cases
+ 	# where the VR4130 errata doesn't apply.
+ 
+ 	mfhi	$2
+ 	mult	$2,$2	# 2 nops
+ 
+ 	mfhi	$2
+ 	addiu	$2,1
+ 	mult	$3,$3	# 1 nop
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	mult	$2,$2	# 1 nop
+ 
+ 	# PART E
+ 	#
+ 	# Check for branches whose targets might be affected.
+ 
+ 	mfhi	$2
+ 	bnez	$3,1f	# 2 nops for normal mode, 3 for mips16
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	bnez	$3,1f	# 1 nop for normal mode, 2 for mips16
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$3,1
+ 	bnez	$3,1f	# 0 nops for normal mode, 1 for mips16
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$3,1
+ 	addiu	$3,1
+ 	bnez	$3,1f	# 0 nops
+ 
+ 	# PART F
+ 	#
+ 	# As above, but with no dependencies between the branch and
+ 	# the previous instruction.  The final branch can use the
+ 	# preceding addiu as its delay slot.
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	bnez	$4,1f	# 1 nop for normal mode, 2 for mips16
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	bnez	$5,1f	# 0 nops for normal mode, 1 for mips16
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	bnez	$6,1f	# 0 nops, fill delay slot in normal mode
+ 1:
+ 
+ 	# PART G
+ 	#
+ 	# Like part B, but check that intervening .set noreorders don't
+ 	# affect the number of nops.
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	.set	reorder
+ 	mult	$4,$4	# 3 nops
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	.set	reorder
+ 	addiu	$4,1
+ 	mult	$5,$5	# 2 nops
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	.set	noreorder
+ 	addiu	$4,1
+ 	.set	reorder
+ 	mult	$5,$5	# 2 nops
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	.set	reorder
+ 	mult	$5,$5	# 2 nops
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	.set	noreorder
+ 	addiu	$4,1
+ 	.set	reorder
+ 	addiu	$5,1
+ 	mult	$6,$6	# 1 nop
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	.set	reorder
+ 	mult	$6,$6	# 1 nop
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	addiu	$6,1
+ 	.set	reorder
+ 	mult	$7,$7	# 0 nops
+ 
+ 	# PART H
+ 	#
+ 	# Like part B, but the mult occurs in a .set noreorder block.
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	mult	$3,$3	# 4 nops
+ 	.set	reorder
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	mult	$4,$4	# 3 nops
+ 	.set	reorder
+ 
+ 	mfhi	$2
+ 	addiu	$3,1
+ 	.set	noreorder
+ 	addiu	$4,1
+ 	mult	$5,$5	# 2 nops
+ 	.set	reorder
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	mult	$6,$6	# 1 nop
+ 	.set	reorder
+ 
+ 	mfhi	$2
+ 	.set	noreorder
+ 	addiu	$3,1
+ 	addiu	$4,1
+ 	addiu	$5,1
+ 	addiu	$6,1
+ 	mult	$7,$7	# 0 nops
+ 	.set	reorder
+ 
+ 	# PART I
+ 	#
+ 	# Check every affected multiplication and division instruction.
+ 
+ 	check2	mult
+ 	check2	multu
+ 	check2	dmult
+ 	check2	dmultu
+ 
+ 	check3	div
+ 	check3	divu
+ 	check3	ddiv
+ 	check3	ddivu
+ 
+ 	.end	\func
+ 	.endm
+ 
+ 	.set	nomips16
+ 	main	foo
+ 
+ 	# PART J
+ 	#
+ 	# Check every affected multiply-accumulate instruction.
+ 
+ 	check3	macc
+ 	check3	macchi
+ 	check3	macchis
+ 	check3	macchiu
+ 	check3	macchius
+ 	check3	maccs
+ 	check3	maccu
+ 	check3	maccus
+ 
+ 	check3	dmacc
+ 	check3	dmacchi
+ 	check3	dmacchis
+ 	check3	dmacchiu
+ 	check3	dmacchius
+ 	check3	dmaccs
+ 	check3	dmaccu
+ 	check3	dmaccus
+ 
+ 	# PART K
+ 	#
+ 	# Check that mtlo and mthi are exempt from the VR4130 errata,
+ 	# although the usual interlocking delay applies.
+ 
+ 	mflo	$2
+ 	mtlo	$3
+ 
+ 	mflo	$2
+ 	mthi	$3
+ 
+ 	mfhi	$2
+ 	mtlo	$3
+ 
+ 	mfhi	$2
+ 	mthi	$3
+ 
+ 	.set	mips16
+ 	main	bar

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11]
  2005-03-08 14:39 Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Richard Sandiford
  2005-03-08 14:42 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Richard Sandiford
@ 2005-03-08 19:06 ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:06 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 	* config/tc-mips.h (mips_cl_insn): Move definition to...
> 	* config/tc-mips.c (mips_cl_insn): ...here.  Add new fields:
> 	frag, where, fixp, reloc_type, valid_p, noreorder_p, delay_slot_p
> 	and extended_p.
> 	(history): New variable.
> 	(prev_insn, prev_prev_insn, prev_insn_valid, prev_insn_frag)
> 	(prev_insn_where, prev_insn_reloc_type, prev_insn_fixp)
> 	(prev_insn_is_delay_slot, prev_insn_unreordered, prev_insn_extended)
> 	(prev_prev_insn_unreordered): Delete.
> 	(reg_needs_delay, append_insn, mips_no_prev_insn, mips_emit_delays)
> 	(macro_start): Replace uses of prev_insn* with the equivalent history[]
> 	field.

OK for mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11]
  2005-03-08 14:42 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Richard Sandiford
  2005-03-08 14:46   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Richard Sandiford
@ 2005-03-08 19:07   ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:07 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 	* config/tc-mips.c (mips_cl_insn): Replace reloc_type array with
> 	a single mips16_absolute_jump_p bit.
> 	(append_insn): Adjust accordingly.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11]
  2005-03-08 14:46   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Richard Sandiford
  2005-03-08 14:50     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Richard Sandiford
@ 2005-03-08 19:08     ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:08 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 
> 
> 
> 	* config/tc-mips.c (mips_cl_insn): Replace valid_p, delay_slot_p
> 	and extended_p fields with a single fixed_p field.
> 	(append_insn, mips_no_prev_insn): Adjust accordingly.

OK for mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11]
  2005-03-08 14:50     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Richard Sandiford
  2005-03-08 14:56       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Richard Sandiford
@ 2005-03-08 19:09       ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:09 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 
> 	* config/tc-mips.c (INSERT_BITS, EXTRACT_BITS, INSERT_OPERAND)
> 	(EXTRACT_OPERAND, MIPS16_INSERT_OPERAND, MIPS16_EXTRACT_OPERAND): New.
> 	(insn_uses_reg, reg_needs_delay, append_insn, macro_build)
> 	(mips16_macro_build, macro_build_lui, mips16_macro, mips_ip)
> 	(mips16_ip): Use the new macros instead of explicit masks and shifts.

Nice. OK for mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11]
  2005-03-08 15:00         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Richard Sandiford
  2005-03-08 15:05           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Richard Sandiford
@ 2005-03-08 19:12           ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:12 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 	* config/tc-mips.c (append_insn): Remove now-redundant nops != 0
> 	check from branch delay code.  Remove unnecessary check for branches.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11]
  2005-03-08 14:56       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Richard Sandiford
  2005-03-08 15:00         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Richard Sandiford
@ 2005-03-08 19:12         ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:12 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 
> 	* config/tc-mips.c (dummy_opcode): Delete.
> 	(nop_insn, mips16_nop_insn): New variables.
> 	(NOP_INSN): New macro.
> 	(insn_length, create_insn, install_insn, move_insn, add_fixed_insn)
> 	(add_relaxed_insn, insert_into_history, emit_nop): New functions.
> 	(md_begin): Initialize nop_insn and mips16_nop_insn.
> 	(append_insn): Use the new emit_nop function to add nops, recording
> 	them in the history buffer.  Use add_fixed_insn or add_relaxed_insn
> 	to reserve room for the instruction and install_insn to install the
> 	final form.  Use insert_into_history to record the instruction in
> 	the history buffer.  Use move_insn to do delay slot filling.
> 	(mips_emit_delays): Use add_fixed_insn instead of the emit_nop macro.
> 	(macro_build, mips16_macro_build, macro_build_lui, mips_ip)
> 	(mips16_ip): Use create_insn to initialize mips_cl_insns.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11]
  2005-03-08 15:05           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Richard Sandiford
  2005-03-08 15:06             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Richard Sandiford
@ 2005-03-08 19:18             ` Eric Christopher
  2005-03-09  9:55               ` Richard Sandiford
  1 sibling, 1 reply; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:18 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 
> 	* config/tc-mips.c (MAX_NOPS): New macro.
> 	(history): Resize to 1 + MAX_NOPS.
> 	(fix_vr4120_class): New enumeration.
> 	(vr4120_conflicts): New variable.
> 	(init_vr4120_conflicts): New function.
> 	(md_begin): Call it.
> 	(insn_uses_reg): Constify first argument.
> 	(classify_vr4120_insn, nops_between, nops_for_insn, nops_for_sequence)
> 	(nops_for_insn_or_target): New functions.
> 	(append_insn): Use the new nops_for_* functions instead of inline
> 	delay checks.  Generalize prev_nop_frag handling to handle an
> 	arbitrary history length.  Insert nops into the history buffer
> 	once the number of nops in prev_nop_frag is fixed.
> 	(emit_delays): Use nops_for_insn instead of inline delay checks.

Instead of nops_between I think I'd like insns_between perhaps? The nop
handling code is strictly for nops, but nops_between just returns a
count of instructions needed between. You can change the name as a
preapproved add on patch though. Don't worry about it now.

OK for mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11]
  2005-03-08 15:06             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Richard Sandiford
  2005-03-08 15:10               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Richard Sandiford
@ 2005-03-08 19:19               ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:19 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 	* config/tc-mips.c (mips_move_labels): New function, taken from...
> 	(append_insn, mips_emit_delays): ...here.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11]
  2005-03-08 15:10               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Richard Sandiford
  2005-03-08 15:12                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Richard Sandiford
@ 2005-03-08 19:42                 ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:42 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> 
> 	* config/tc-mips.h (mips_flush_pending_output): Delete.
> 	(mips_emit_delays): Declare.
> 	(md_flush_pending_output): Use mips_emit_delays.
> 	* config/tc-mips.c (mips_no_prev_insn): Remove parameter; always forget
> 	the previous instructions.
> 	(md_begin, append_insn, md_parse_option): Update callers.
> 	(mips_emit_delay): Remove parameter.  Move INSNS != 0 code to
> 	start_noreorder.
> 	(mips_align, s_change_sec, s_cons, s_float_cons, s_gpword)
> 	(s_gpdword): Update callers.
> 	(start_noreorder, end_noreorder): New functions.
> 	(macro, macro2, mips16_macro, s_mipsset): Use them instead of
> 	manipulating mips_opts or prev_nop_frag directly.
> 	(mips_flush_pending_output): Delete.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11]
  2005-03-08 15:12                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Richard Sandiford
  2005-03-08 15:16                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11] Richard Sandiford
@ 2005-03-08 19:43                   ` Eric Christopher
  1 sibling, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:43 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?
> 
> Richard
> 
> 
> 
> 	* config/tc-mips.c (append_insn): Remove cop_interlocks test from
> 	branch delay code.
> 
> testsuite/
> 	* gas/mips/relax-swap1-mips[12].d: Expect the delay slots of
> 	bc1f and bc1t to be filled.
> 	* gas/mips/branch-misc-3.[sd]: New test.
> 	* gas/mips/mips.exp: Run it.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11]
  2005-03-08 15:16                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11] Richard Sandiford
@ 2005-03-08 19:45                     ` Eric Christopher
  0 siblings, 0 replies; 23+ messages in thread
From: Eric Christopher @ 2005-03-08 19:45 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: binutils


> Tested on mips64{,el}-linux-gnu and mipsisa64{,el}-elf.  OK to install?
> 
> Richard
> 
> 
> 	* config/tc-mips.c (MAX_VR4130_NOPS, MAX_DELAY_NOPS): New macros.
> 	(MAX_NOPS): Bump to 4.
> 	(mips_fix_vr4130): New variable.
> 	(nops_for_vr4130): New function.
> 	(nops_for_insn): Use MAX_DELAY_NOPS rather than MAX_NOPS.  Use
> 	nops_for_vr4130 if working around VR4130 errata.
> 	(OPTION_FIX_VR4130, OPTION_NO_FIX_VR4130): New macros.
> 	(md_longopts): Add -mfix-vr4130 and -mno-fix-vr4130.
> 	(md_parse_option): Handle them.
> 	(md_show_usage): Print them.
> 	* doc/c-mips.texi: Document -mfix-vr4130 and -mno-fix-vr4130.

OK mainline and branch.

-eric

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11]
  2005-03-08 19:18             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Eric Christopher
@ 2005-03-09  9:55               ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2005-03-09  9:55 UTC (permalink / raw)
  To: Eric Christopher; +Cc: binutils

Eric Christopher <echristo@redhat.com> writes:
> Instead of nops_between I think I'd like insns_between perhaps?

OK, patches installed with that change.

Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2005-03-09  9:55 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-08 14:39 Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Richard Sandiford
2005-03-08 14:42 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Richard Sandiford
2005-03-08 14:46   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Richard Sandiford
2005-03-08 14:50     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Richard Sandiford
2005-03-08 14:56       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Richard Sandiford
2005-03-08 15:00         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Richard Sandiford
2005-03-08 15:05           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Richard Sandiford
2005-03-08 15:06             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Richard Sandiford
2005-03-08 15:10               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Richard Sandiford
2005-03-08 15:12                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Richard Sandiford
2005-03-08 15:16                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [11/11] Richard Sandiford
2005-03-08 19:45                     ` Eric Christopher
2005-03-08 19:43                   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [10/11] Eric Christopher
2005-03-08 19:42                 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [9/11] Eric Christopher
2005-03-08 19:19               ` Rework MIPS nop-insertion code, add -mfix-vr4130 [8/11] Eric Christopher
2005-03-08 19:18             ` Rework MIPS nop-insertion code, add -mfix-vr4130 [7/11] Eric Christopher
2005-03-09  9:55               ` Richard Sandiford
2005-03-08 19:12           ` Rework MIPS nop-insertion code, add -mfix-vr4130 [6/11] Eric Christopher
2005-03-08 19:12         ` Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11] Eric Christopher
2005-03-08 19:09       ` Rework MIPS nop-insertion code, add -mfix-vr4130 [4/11] Eric Christopher
2005-03-08 19:08     ` Rework MIPS nop-insertion code, add -mfix-vr4130 [3/11] Eric Christopher
2005-03-08 19:07   ` Rework MIPS nop-insertion code, add -mfix-vr4130 [2/11] Eric Christopher
2005-03-08 19:06 ` Rework MIPS nop-insertion code, add -mfix-vr4130 [1/11] Eric Christopher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).