This is the mail archive of the binutils@sourceware.org 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]

Re: [PATCH] MIPS: microMIPS ASE support


Hi Richard,

On Tue, 26 Jul 2011, Maciej W. Rozycki wrote:

> > and I gather from an off-list discussion a couple of months ago that
> > there were indeed some things that you didn't like.  But I think it'd
> > be easier to deal with them as follow-ups.  Please feel free to send
> > patches against trunk.  Or, if you tell me what it is you disagree with,
> > I can try to fix it myself.
> 
>  I guess I'll just send off the e-mail I had been writing but never 
> actually completed.  My current state of the changes includes all my 
> updates that reflect the points made, but now I'll have to regenerate 
> them, possibly by reverting yours, applying mine on top and figuring out 
> what differences to the original remain.  Oh well...

 Here's what I have come up with as a result of merging your changes into 
my code base.  There are plenty of small changes, so I have decided not to 
put too much effort into straightening them up (or not) lest you are 
unhappy with the outcome anyway.  Instead, I'm giving you (and the others) 
an opportunity to review my code in its current shape.  The result 
generally reflects my concerns as expressed earlier this week, in response 
to your comments back in March.

 Note there are a couple of bug fixes, some optimisations and one 
functional improvement too -- see the change log for details.

> > I'm sure there are things that we've both missed, but again,
> > we can deal with them as follow-ups.
> 
>  There's a whole lot of important linker relaxation fixes that I reckon 
> were not included in the original series plus several bug fixes.

 I'll work on these fixes now -- there are quite a few and at least one 
still requires some work not to be considered a dirty hack -- and will be 
back with you shortly.

 Comments, questions?

2011-07-28  Maciej W. Rozycki  <macro@codesourcery.com>

	bfd/
	* elfxx-mips.c: Adjust comments throughout.
	(mips_elf_relax_delete_bytes): Reshape code.
	(bz_insn_16): Correct opcode mask.
	(check_br32): Fix return type.
	(check_4byte_branch): Remove function.
	(check_bzc): New function.
	(_bfd_mips_elf_relax_section): Permit the relaxation of LUI
	instructions that immediately follow a compact branch
	instruction.  Remove check for R_MICROMIPS_GPREL16 relocations.  
	Reshape code.

	gas/
	* config/tc-mips.c: Adjust comments throughout.
	(reglist_lookup): Reshape code.
	(jmp_reloc_p, jalr_reloc_p): Reformat.
	(got16_reloc_p, hi16_reloc_p, lo16_reloc_p): Handle microMIPS
	relocations.
	(gpr_mod_mask): Remove unused variable.  Reshape code.
	(gpr_read_mask, gpr_write_mask): Reshape code.
	(fpr_read_mask, fpr_write_mask): Likewise.
	(nops_for_vr4130): Ensure non-microMIPS mode.
	(can_swap_branch_p): Correct pinfo2 reference.  Reshape code.
	(append_insn): Skip Loongson 2F workaround in MIPS16 mode.  Use
	the outermost operator of a compound relocation to determines
	the relocated field.  Reshape code.
	(md_convert_frag): Reshape code.

	include/opcode/
	* mips.h: Clarify the description of microMIPS instruction
	manipulation macros.
	(MICROMIPSOP_MASK_MAJOR, MICROMIPSOP_SH_MAJOR): Remove macros.

  Maciej

r-binutils-20110225-umips-fix.diff
Index: binutils-fsf-trunk-quilt/gas/config/tc-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/config/tc-mips.c	2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/config/tc-mips.c	2011-07-28 23:30:26.000000000 +0100
@@ -483,7 +483,7 @@ static int mips_32bitmode = 0;
    (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0		\
     || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
 
-/* Return true if the given CPU supports microMIPS.  */
+/* Return true if the given CPU supports the microMIPS ASE.  */
 #define CPU_HAS_MICROMIPS(cpu)	0
 
 /* True if CPU has a dror instruction.  */
@@ -2141,7 +2141,7 @@ reg_lookup (char **s, unsigned int types
    As a special exception if one of s0-s7 registers is specified as
    the range's lower delimiter and s8 (fp) is its upper one, then no
    registers whose numbers place them between s7 and s8 (i.e. $24-$29)
-   are selected; they have to be named separately if needed.  */
+   are selected; they have to be listed separately if needed.  */
 
 static int
 reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
@@ -2150,9 +2150,9 @@ reglist_lookup (char **s, unsigned int t
   unsigned int lastregno;
   bfd_boolean ok = TRUE;
   unsigned int regmask;
-  unsigned int regno;
+  char *s_endlist = *s;
   char *s_reset = *s;
-  char *s_end_of_list = *s;
+  unsigned int regno;
 
   while (reg_lookup (s, types, &regno))
     {
@@ -2177,14 +2177,14 @@ reglist_lookup (char **s, unsigned int t
       regmask ^= (1 << regno) - 1;
       reglist |= regmask;
 
-      s_end_of_list = *s;
+      s_endlist = *s;
       if (**s != ',')
 	break;
       (*s)++;
     }
 
   if (ok)
-    *s = s_end_of_list;
+    *s = s_endlist;
   else
     *s = s_reset;
   if (reglistp)
@@ -2663,41 +2663,36 @@ micromips_reloc_p (bfd_reloc_code_real_t
 }
 
 static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
+}
+
+static inline bfd_boolean
 got16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_MIPS_GOT16
-	  || reloc == BFD_RELOC_MIPS16_GOT16
+  return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
 	  || reloc == BFD_RELOC_MICROMIPS_GOT16);
 }
 
 static inline bfd_boolean
 hi16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_HI16_S
-	  || reloc == BFD_RELOC_MIPS16_HI16_S
+  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
 	  || reloc == BFD_RELOC_MICROMIPS_HI16_S);
 }
 
 static inline bfd_boolean
 lo16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_LO16
-	  || reloc == BFD_RELOC_MIPS16_LO16
+  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
 	  || reloc == BFD_RELOC_MICROMIPS_LO16);
 }
 
 static inline bfd_boolean
-jmp_reloc_p (bfd_reloc_code_real_type reloc)
-{
-  return (reloc == BFD_RELOC_MIPS_JMP
-	  || reloc == BFD_RELOC_MICROMIPS_JMP);
-}
-
-static inline bfd_boolean
 jalr_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_MIPS_JALR
-	  || reloc == BFD_RELOC_MICROMIPS_JALR);
+  return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
 }
 
 /* Return true if the given relocation might need a matching %lo().
@@ -2893,18 +2888,21 @@ relax_end (void)
   mips_relax.sequence = 0;
 }
 
-/* Return the mask of core registers that instruction IP may
-   read or write.  */
+/* Return the mask of core registers that IP reads or writes.  */
 
 static unsigned int
 gpr_mod_mask (const struct mips_cl_insn *ip)
 {
-  unsigned long pinfo, pinfo2;
+  unsigned long pinfo2;
   unsigned int mask;
 
   mask = 0;
-  pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
+  if (!mips_opts.mips16)
+    {
+      if (pinfo2 & INSN2_MOD_SP)
+	mask |= 1 << SP;
+    }
   if (mips_opts.micromips)
     {
       if (pinfo2 & INSN2_MOD_GPR_MB)
@@ -2934,8 +2932,6 @@ gpr_mod_mask (const struct mips_cl_insn 
 	mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
       if (pinfo2 & INSN2_MOD_GPR_MQ)
 	mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
-      if (pinfo2 & INSN2_MOD_SP)
-	mask |= 1 << SP;
     }
   return mask;
 }
@@ -2969,27 +2965,20 @@ gpr_read_mask (const struct mips_cl_insn
       if (pinfo & MIPS16_INSN_READ_GPR_X)
 	mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
     }
-  else if (mips_opts.micromips)
-    {
-      if (pinfo & INSN_READ_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
-      if (pinfo & INSN_READ_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
-      if (pinfo2 & INSN2_READ_GPR_31)
-	mask |= 1 << RA;
-      if (pinfo2 & INSN2_READ_GP)
-	mask |= 1 << GP;
-    }
   else
     {
       if (pinfo2 & INSN2_READ_GPR_D)
-	mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
       if (pinfo & INSN_READ_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
       if (pinfo & INSN_READ_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+      if (pinfo2 & INSN2_READ_GP)
+	mask |= 1 << GP;
+      if (pinfo2 & INSN2_READ_GPR_31)
+	mask |= 1 << RA;
       if (pinfo2 & INSN2_READ_GPR_Z)
-	mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
     }
   /* Don't include register 0.  */
   return mask & ~1;
@@ -3023,23 +3012,14 @@ gpr_write_mask (const struct mips_cl_ins
       if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
 	mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
     }
-  else if (mips_opts.micromips)
-    {
-      if (pinfo & INSN_WRITE_GPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
-      if (pinfo & INSN_WRITE_GPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
-      if (pinfo2 & INSN2_WRITE_GPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
-      if (pinfo & INSN_WRITE_GPR_31)
-	mask |= 1 << RA;
-    }
   else
     {
       if (pinfo & INSN_WRITE_GPR_D)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
       if (pinfo & INSN_WRITE_GPR_T)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
+      if (pinfo2 & INSN2_WRITE_GPR_S)
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
       if (pinfo & INSN_WRITE_GPR_31)
 	mask |= 1 << RA;
       if (pinfo2 & INSN2_WRITE_GPR_Z)
@@ -3060,19 +3040,10 @@ fpr_read_mask (const struct mips_cl_insn
   mask = 0;
   pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
-  if (mips_opts.micromips)
+  if (!mips_opts.mips16)
     {
       if (pinfo2 & INSN2_READ_FPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
-      if (pinfo & INSN_READ_FPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
-      if (pinfo & INSN_READ_FPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
-      if (pinfo & INSN_READ_FPR_R)
-	mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
-    }
-  else if (!mips_opts.mips16)
-    {
+	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
       if (pinfo & INSN_READ_FPR_S)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
       if (pinfo & INSN_READ_FPR_T)
@@ -3100,16 +3071,7 @@ fpr_write_mask (const struct mips_cl_ins
   mask = 0;
   pinfo = ip->insn_mo->pinfo;
   pinfo2 = ip->insn_mo->pinfo2;
-  if (mips_opts.micromips)
-    {
-      if (pinfo2 & INSN_WRITE_FPR_D)
-	mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
-      if (pinfo & INSN_WRITE_FPR_S)
-	mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
-      if (pinfo & INSN_WRITE_FPR_T)
-	mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
-    }
-  else if (!mips_opts.mips16)
+  if (!mips_opts.mips16)
     {
       if (pinfo & INSN_WRITE_FPR_D)
 	mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
@@ -3316,6 +3278,7 @@ nops_for_vr4130 (int ignore, const struc
     if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
       {
 	/* Extract the destination register.  */
+	gas_assert (!mips_opts.micromips);
 	mask = gpr_write_mask (&hist[i]);
 
 	/* No nops are needed if INSN reads that register.  */
@@ -3720,8 +3683,9 @@ can_swap_branch_p (struct mips_cl_insn *
     return FALSE;
 
   /* If the previous instruction is in a variant frag other than this
-     branch's one, we cannot do the swap.  This does not apply to the
-     mips16, which uses variant frags for different purposes.  */
+     branch's one, we cannot do the swap.  This does not apply to
+     MIPS16/microMIPS code, which uses variant frags for different
+     purposes.  */
   if (!HAVE_CODE_COMPRESSION
       && history[0].frag
       && history[0].frag->fr_type == rs_machine_dependent)
@@ -3781,17 +3745,16 @@ can_swap_branch_p (struct mips_cl_insn *
 
   /* If the previous instruction has an incorrect size for a fixed
      branch delay slot in microMIPS mode, we cannot swap.  */
-  if (mips_opts.micromips)
-    {
-      pinfo2 = ip->insn_mo->pinfo;
-      if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT)
-	  && insn_length (history) != 2)
-	return FALSE;
+  pinfo2 = ip->insn_mo->pinfo2;
+  if (mips_opts.micromips
+      && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+      && insn_length (history) != 2)
+    return FALSE;
+  if (mips_opts.micromips
+      && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+      && insn_length (history) != 4)
+    return FALSE;
 
-      if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT)
-	  && insn_length (history) != 4)
-	return FALSE;
-    }
   return TRUE;
 }
 
@@ -3984,10 +3947,10 @@ append_insn (struct mips_cl_insn *ip, ex
 {
   unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2;
   bfd_boolean relaxed_branch = FALSE;
-  bfd_boolean relax32;
   enum append_method method;
+  bfd_boolean relax32;
 
-  if (mips_fix_loongson2f && !mips_opts.micromips)
+  if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
     fix_loongson2f (ip);
 
   mips_mark_labels ();
@@ -4014,10 +3977,11 @@ append_insn (struct mips_cl_insn *ip, ex
   else if (*reloc_type <= BFD_RELOC_UNUSED
 	   && address_expr->X_op == O_constant)
     {
+      bfd_reloc_code_real_type orig_reloc = *reloc_type;
       unsigned int tmp;
 
       ip->complete_p = 1;
-      switch (*reloc_type)
+      switch (orig_reloc)
 	{
 	case BFD_RELOC_32:
 	  ip->insn_opcode |= address_expr->X_add_number;
@@ -4192,9 +4156,9 @@ append_insn (struct mips_cl_insn *ip, ex
      If the instruction produced is a branch that we will swap with
      the preceding instruction, then we add the displacement by which
      the branch will be moved backwards.  This is more appropriate
-     and for MIPS16/microMIPS code also prevents a debugger from placing
-     a breakpoint in the middle of the branch (and corrupting code if
-     software breakpoints are used).  */
+     and for MIPS16/microMIPS code also prevents a debugger from
+     placing a breakpoint in the middle of the branch (and corrupting
+     code if software breakpoints are used).  */
   dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0)
 		    + (method == APPEND_SWAP ? insn_length (history) : 0));
 #endif
@@ -4329,60 +4293,66 @@ append_insn (struct mips_cl_insn *ip, ex
 
   if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
     {
+      bfd_reloc_code_real_type orig_reloc = *reloc_type;
       bfd_reloc_code_real_type final_type[3];
+      reloc_howto_type *howto0;
       reloc_howto_type *howto;
+      int n;
       int i;
 
       /* Perform any necessary conversion to microMIPS relocations
-	 and find out how many relocations there actually are.  */
-      for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
-	final_type[i] = micromips_map_reloc (reloc_type[i]);
+         and find out how many relocations there actually are.  */
+      for (n = 0; n < 3 && reloc_type[n] != BFD_RELOC_UNUSED; n++)
+	final_type[n] = micromips_map_reloc (reloc_type[n]);
 
       /* In a compound relocation, it is the final (outermost)
 	 operator that determines the relocated field.  */
-      howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+      howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[n - 1]);
+
       if (howto == NULL)
 	{
 	  /* To reproduce this failure try assembling gas/testsuites/
 	     gas/mips/mips16-intermix.s with a mips-ecoff targeted
 	     assembler.  */
 	  as_bad (_("Unsupported MIPS relocation number %d"),
-		  final_type[i - 1]);
+		  final_type[n - 1]);
 	  howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
 	}
-	  
-      howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
+
+      if (n > 1)
+	howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
       ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
 				 bfd_get_reloc_size (howto),
 				 address_expr,
-				 howto->pc_relative, final_type[0]);
+				 howto0 && howto0->pc_relative,
+				 final_type[0]);
 
       /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
-      if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
-	  && ip->fixp[0]->fx_addsy)
+      if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
 	*symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
 
       /* These relocations can have an addend that won't fit in
-	 4 octets for 64bit assembly.  */
+         4 octets for 64bit assembly.  We cheat and check orig_reloc
+         here as this has fewer choices than reloc.  */
       if (HAVE_64BIT_GPRS
 	  && ! howto->partial_inplace
-	  && (reloc_type[0] == BFD_RELOC_16
-	      || reloc_type[0] == BFD_RELOC_32
-	      || reloc_type[0] == BFD_RELOC_MIPS_JMP
-	      || reloc_type[0] == BFD_RELOC_GPREL16
-	      || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
-	      || reloc_type[0] == BFD_RELOC_GPREL32
-	      || reloc_type[0] == BFD_RELOC_64
-	      || reloc_type[0] == BFD_RELOC_CTOR
-	      || reloc_type[0] == BFD_RELOC_MIPS_SUB
-	      || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
-	      || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
-	      || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
-	      || reloc_type[0] == BFD_RELOC_MIPS_REL16
-	      || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
-	      || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
-	      || hi16_reloc_p (reloc_type[0])
-	      || lo16_reloc_p (reloc_type[0])))
+	  && (orig_reloc == BFD_RELOC_16
+	      || orig_reloc == BFD_RELOC_32
+	      || orig_reloc == BFD_RELOC_MIPS_JMP
+	      || orig_reloc == BFD_RELOC_GPREL16
+	      || orig_reloc == BFD_RELOC_MIPS_LITERAL
+	      || orig_reloc == BFD_RELOC_GPREL32
+	      || orig_reloc == BFD_RELOC_64
+	      || orig_reloc == BFD_RELOC_CTOR
+	      || orig_reloc == BFD_RELOC_MIPS_SUB
+	      || orig_reloc == BFD_RELOC_MIPS_HIGHEST
+	      || orig_reloc == BFD_RELOC_MIPS_HIGHER
+	      || orig_reloc == BFD_RELOC_MIPS_SCN_DISP
+	      || orig_reloc == BFD_RELOC_MIPS_REL16
+	      || orig_reloc == BFD_RELOC_MIPS_RELGOT
+	      || orig_reloc == BFD_RELOC_MIPS16_GPREL
+	      || hi16_reloc_p (orig_reloc)
+	      || lo16_reloc_p (orig_reloc)))
 	ip->fixp[0]->fx_no_overflow = 1;
 
       if (mips_relax.sequence)
@@ -4390,7 +4360,7 @@ append_insn (struct mips_cl_insn *ip, ex
 	  if (mips_relax.first_fixup == 0)
 	    mips_relax.first_fixup = ip->fixp[0];
 	}
-      else if (reloc_needs_lo_p (*reloc_type))
+      else if (reloc_needs_lo_p (final_type[0]))
 	{
 	  struct mips_hi_fixup *hi_fixup;
 
@@ -4413,17 +4383,16 @@ append_insn (struct mips_cl_insn *ip, ex
 	 against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
 	 moment we only use RSS_UNDEF, but we could add support
 	 for the others if it ever becomes necessary.  */
-      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, final_type[i]);
+      for (i = 1; i < n; i++)
+	{
+	  ip->fixp[i] = fix_new (ip->frag, ip->where,
+				 ip->fixp[0]->fx_size, NULL, 0,
+				 FALSE, final_type[i]);
 
-	    /* Use fx_tcbit to mark compound relocs.  */
-	    ip->fixp[0]->fx_tcbit = 1;
-	    ip->fixp[i]->fx_tcbit = 1;
-	  }
+	  /* Use fx_tcbit to mark compound relocs.  */
+	  ip->fixp[0]->fx_tcbit = 1;
+	  ip->fixp[i]->fx_tcbit = 1;
+	}
     }
   install_insn (ip);
 
@@ -17800,8 +17769,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
       bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
       int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
-      unsigned long jal, jalr, jr;
-
+      bfd_boolean short_ds;
       unsigned long insn;
       expressionS exp;
       fixS *fixp;
@@ -17812,7 +17780,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 
       fragp->fr_fix += fragp->fr_var;
 
-      /* Handle 16-bit branches that fit or are forced to fit.  */
+      /* Handle 16-bit branches that fit or forced to fit.  */
       if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
 	{
 	  /* We generate a fixup instead of applying it right now,
@@ -17841,7 +17809,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 	  return;
 	}
 
-      /* Handle 32-bit branches that fit or forced to fit.  */
+      /* Handle 32-bit branches that fit or are forced to fit.  */
       if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
 	  || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
 	{
@@ -17914,18 +17882,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       as_warn_where (fragp->fr_file, fragp->fr_line,
 		     _("Relaxed out-of-range branch into a jump"));
 
-      /* Check the short-delay-slot bit.  */
-      if (al && (insn & 0x02000000) != 0)
-	{
-	  jal = 0x74000000;				/* jals  */
-	  jalr = 0x45e0;				/* jalrs  */
-	}
-      else
-	{
-	  jal = 0xf4000000;				/* jal  */
-	  jalr = 0x45c0;				/* jalr  */
-	}
-      jr = compact ? 0x45a0 : 0x4580;			/* jr/c  */
+      /* Set the short-delay-slot bit.  */
+      short_ds = al && (insn & 0x02000000) != 0;
 
       if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
 	{
@@ -17995,6 +17953,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
 
       if (mips_pic == NO_PIC)
 	{
+	  unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s  */
+
 	  /* j/jal/jals <sym>  R_MICROMIPS_26_S1  */
 	  insn = al ? jal : 0xd4000000;
 
@@ -18019,6 +17979,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU
       else
 	{
 	  unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
+	  unsigned long jalr = short_ds ? 0x45e0 : 0x45c0;	/* jalr/s  */
+	  unsigned long jr = compact ? 0x45a0 : 0x4580;		/* jr/c  */
 
 	  /* lw/ld $at, <sym>($gp)  R_MICROMIPS_GOT16  */
 	  insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c	2011-07-28 23:18:50.000000000 +0100
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c	2011-07-28 23:30:26.000000000 +0100
@@ -11910,8 +11910,7 @@ mips_elf_relax_delete_bytes (bfd *abfd,
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
   for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
-    if (isym->st_shndx == sec_shndx
-	&& isym->st_value > addr)
+    if (isym->st_shndx == sec_shndx && isym->st_value > addr)
       isym->st_value -= count;
 
   /* Now adjust the global symbols defined in this section.  */
@@ -11928,9 +11927,8 @@ mips_elf_relax_delete_bytes (bfd *abfd,
 	   || sym_hash->root.type == bfd_link_hash_defweak)
 	  && sym_hash->root.u.def.section == sec)
 	{
-	  bfd_vma value;
+	  bfd_vma value = sym_hash->root.u.def.value;
 
-	  value = sym_hash->root.u.def.value;
 	  if (ELF_ST_IS_MICROMIPS (sym_hash->other))
 	    value &= MINUS_TWO;
 	  if (value > addr)
@@ -11989,7 +11987,7 @@ static const struct opcode_descriptor b_
   { /* "b",	"mD",		*/ 0xcc00,     0xfc00 };
 
 static const struct opcode_descriptor bz_insn_16 =
-  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xac00 };
+  { /* "b(eq|ne)z", "md,mE",	*/ 0x8c00,     0xdc00 };
 
 
 /* 32-bit and 16-bit branch EQ and NE zero.  */
@@ -12241,7 +12239,7 @@ check_br16 (bfd *abfd, bfd_byte *ptr, un
 /* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
    then return TRUE, otherwise FALSE.  */
 
-static int
+static bfd_boolean
 check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
 {
   unsigned long opcode;
@@ -12266,32 +12264,37 @@ check_br32 (bfd *abfd, bfd_byte *ptr, un
   return FALSE;
 }
 
-/* Bitsize checking.  */
-#define IS_BITSIZE(val, N)						\
-  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))		\
-    - (1ULL << ((N) - 1))) == (val))
-
-/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
-   is a 4-byte branch at offset OFFSET.  */
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+   IRELEND) at OFFSET indicate that it is a compact branch there, then
+   return TRUE, otherwise FALSE.  */
 
 static bfd_boolean
-check_4byte_branch (Elf_Internal_Rela *internal_relocs,
-		    Elf_Internal_Rela *irelend, bfd_vma offset)
+check_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+	   const Elf_Internal_Rela *internal_relocs,
+	   const Elf_Internal_Rela *irelend)
 {
-  Elf_Internal_Rela *irel;
-  unsigned long r_type;
+  const Elf_Internal_Rela *irel;
+  unsigned long opcode;
+
+  opcode   = bfd_get_16 (abfd, ptr);
+  opcode <<= 16;
+  opcode  |= bfd_get_16 (abfd, ptr + 2);
+  if (find_match (opcode, bzc_insns_32) < 0)
+    return FALSE;
 
   for (irel = internal_relocs; irel < irelend; irel++)
-    if (irel->r_offset == offset)
-      {
-	r_type = ELF32_R_TYPE (irel->r_info);
-	if (r_type == R_MICROMIPS_26_S1
-	    || r_type == R_MICROMIPS_PC16_S1
-	    || r_type == R_MICROMIPS_JALR)
-	  return TRUE;
-      }
+    if (irel->r_offset == offset
+	&& ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+      return TRUE;
+
   return FALSE;
 }
+
+/* Bitsize checking.  */
+#define IS_BITSIZE(val, N)						\
+  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))		\
+    - (1ULL << ((N) - 1))) == (val))
+
 
 bfd_boolean
 _bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
@@ -12336,6 +12339,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
       unsigned long opcode;
       bfd_vma symval;
       bfd_vma pcrval;
+      bfd_byte *ptr;
       int fndopc;
 
       /* The number of bytes to delete for relaxation and from where
@@ -12347,8 +12351,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
          this reloc.  */
       if (r_type != R_MICROMIPS_HI16
 	  && r_type != R_MICROMIPS_PC16_S1
-	  && r_type != R_MICROMIPS_26_S1
-	  && r_type != R_MICROMIPS_GPREL16)
+	  && r_type != R_MICROMIPS_26_S1)
 	continue;
 
       /* Get the section contents if we haven't done so already.  */
@@ -12361,6 +12364,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
 	    goto error_return;
 	}
+      ptr = contents + irel->r_offset;
 
       /* Read this BFD's local symbols if we haven't done so already.  */
       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
@@ -12432,8 +12436,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
       if (irel->r_offset + 4 > sec->size)
 	continue;
 
-      opcode  = bfd_get_16 (abfd, contents + irel->r_offset    ) << 16;
-      opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
+      opcode  = bfd_get_16 (abfd, ptr    ) << 16;
+      opcode |= bfd_get_16 (abfd, ptr + 2);
 
       /* This is the pc-relative distance from the instruction the
          relocation is applied to, to the symbol referred.  */
@@ -12452,6 +12456,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
          out the offset).  */
       if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
 	{
+	  bfd_boolean bzc = FALSE;
 	  unsigned long nextopc;
 	  unsigned long reg;
 	  bfd_vma offset;
@@ -12475,19 +12480,19 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	      && ELF32_R_SYM (irel[2].r_info) == r_symndx)
 	    continue;
 
-	  /* See if the LUI instruction *might* be in a branch delay slot.  */
+	  /* See if the LUI instruction *might* be in a branch delay slot.
+	     We check whether what looks like a 16-bit branch or jump is
+	     actually an immediate argument to a compact branch, and let
+	     it through if so.  */
 	  if (irel->r_offset >= 2
-	      && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+	      && check_br16_dslot (abfd, ptr - 2)
 	      && !(irel->r_offset >= 4
-		   /* If the instruction is actually a 4-byte branch,
-		      the value of check_br16_dslot doesn't matter.
-		      We should use check_br32_dslot to check whether
-		      the branch has a delay slot.  */
-		   && check_4byte_branch (internal_relocs, irelend,
-					  irel->r_offset - 4)))
+		   && (bzc = check_bzc (abfd, ptr - 4, irel->r_offset - 4,
+					internal_relocs, irelend))))
 	    continue;
 	  if (irel->r_offset >= 4
-	      && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
+	      && !bzc
+	      && check_br32_dslot (abfd, ptr - 4))
 	    continue;
 
 	  reg = OP32_SREG (opcode);
@@ -12502,11 +12507,11 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	    case 0:
 	      break;
 	    case 2:
-	      if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
+	      if (check_br16 (abfd, ptr + 4, reg))
 		break;
 	      continue;
 	    case 4:
-	      if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
+	      if (check_br32 (abfd, ptr + 4, reg))
 		break;
 	      continue;
 	    default:
@@ -12581,8 +12586,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	       && irel->r_offset + 5 < sec->size
 	       && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
 		   || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
-	       && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
-			 nop_insn_16))
+	       && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
 	{
 	  unsigned long reg;
 
@@ -12593,10 +12597,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 		    | BZC32_REG_FIELD (reg)
 		    | (opcode & 0xffff));		/* Addend value.  */
 
-	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
-		      contents + irel->r_offset);
-	  bfd_put_16 (abfd,  opcode        & 0xffff,
-		      contents + irel->r_offset + 2);
+	  bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
+	  bfd_put_16 (abfd,  opcode        & 0xffff, ptr + 2);
 
 	  /* Delete the 16-bit delay slot NOP: two bytes from
 	     irel->offset + 4.  */
@@ -12617,7 +12619,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  bfd_put_16 (abfd,
 		      (b_insn_16.match
 		       | (opcode & 0x3ff)),		/* Addend value.  */
-		      contents + irel->r_offset);
+		      ptr);
 
 	  /* Delete 2 bytes from irel->r_offset + 2.  */
 	  delcnt = 2;
@@ -12645,7 +12647,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 		      (bz_insns_16[fndopc].match
 		       | BZ16_REG_FIELD (reg)
 		       | (opcode & 0x7f)),		/* Addend value.  */
-		      contents + irel->r_offset);
+		      ptr);
 
 	  /* Delete 2 bytes from irel->r_offset + 2.  */
 	  delcnt = 2;
@@ -12661,14 +12663,13 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	  unsigned long n32opc;
 	  bfd_boolean relaxed = FALSE;
 
-	  n32opc  = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
-	  n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
+	  n32opc  = bfd_get_16 (abfd, ptr + 4) << 16;
+	  n32opc |= bfd_get_16 (abfd, ptr + 6);
 
 	  if (MATCH (n32opc, nop_insn_32))
 	    {
 	      /* Replace delay slot 32-bit NOP with a 16-bit NOP.  */
-	      bfd_put_16 (abfd, nop_insn_16.match,
-			  contents + irel->r_offset + 4);
+	      bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
 
 	      relaxed = TRUE;
 	    }
@@ -12679,7 +12680,7 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 			  (move_insn_16.match
 			   | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
 			   | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
-			  contents + irel->r_offset + 4);
+			  ptr + 4);
 
 	      relaxed = TRUE;
 	    }
@@ -12691,9 +12692,9 @@ _bfd_mips_elf_relax_section (bfd *abfd, 
 	      /* JAL with 32-bit delay slot that is changed to a JALS
 	         with 16-bit delay slot.  */
 	      bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
-			  contents + irel->r_offset);
+			  ptr);
 	      bfd_put_16 (abfd,  jal_insn_32_bd16.match        & 0xffff,
-			  contents + irel->r_offset + 2);
+			  ptr + 2);
 
 	      /* Delete 2 bytes from irel->r_offset + 6.  */
 	      delcnt = 2;
Index: binutils-fsf-trunk-quilt/include/opcode/mips.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/include/opcode/mips.h	2011-07-28 23:29:25.000000000 +0100
+++ binutils-fsf-trunk-quilt/include/opcode/mips.h	2011-07-28 23:30:26.000000000 +0100
@@ -1332,13 +1332,10 @@ extern int bfd_mips_num_opcodes;
 extern const struct mips_opcode mips16_opcodes[];
 extern const int bfd_mips16_num_opcodes;
 
-/* These are the bitmasks and shift counts used for the different
-   fields in the instruction formats.  Other than MAJOR, no masks are
-   provided for the fixed portions of an instruction, since they are
-   not needed.  */
+/* These are the bit masks and shift counts used for the different fields
+   in the microMIPS instruction formats.  No masks are provided for the
+   fixed portions of an instruction, since they are not needed.  */
 
-#define MICROMIPSOP_MASK_MAJOR		0x3f
-#define MICROMIPSOP_SH_MAJOR		26
 #define MICROMIPSOP_MASK_IMMEDIATE	0xffff
 #define MICROMIPSOP_SH_IMMEDIATE	0
 #define MICROMIPSOP_MASK_DELTA		0xffff


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