This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Rework MIPS nop-insertion code, add -mfix-vr4130 [5/11]


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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]