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

[PATCH] bfd sparc64 fixes and tail call optimizations (take 3)


On Tue, May 23, 2000 at 09:47:30AM -0700, Richard Henderson wrote:
> On Tue, May 23, 2000 at 06:06:33PM +0200, Jakub Jelinek wrote:
> > I thought about doing it in relax_section for a while, but I think it would
> > be slower...
> 
> You'd think, but I've never been able to measure a difference
> in link time when doing relaxation on Alpha.
> 
> Anyway, this is fine.
> 

Here is an updated version which uses opcodes/sparc.h and many
symbolic constants to make the code more readable.
If there are no objections, can anybody commit it to CVS, please?
Thanks.

	Jakub
2000-03-09  Jakub Jelinek  <jakub@redhat.com>

	* elf64-sparc.c: Add ATTRIBUTE_UNUSED to unused function parameters.
	Remove unusued variables.
	(sparc64_elf_relocate_section): Change r_symndx type to unsigned long.
	(sparc64_elf_merge_private_bfd_data): Fix shared library case from
	previous fix, so that shared libs really don't influence targets
	extension mask and memory model.

--- bfd/elf64-sparc.c.jj	Thu Mar  9 10:02:10 2000
+++ bfd/elf64-sparc.c	Thu Mar  9 12:01:37 2000
@@ -212,7 +212,7 @@ static CONST struct elf_reloc_map sparc_
 
 static reloc_howto_type *
 sparc64_elf_reloc_type_lookup (abfd, code)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type code;
 {
   unsigned int i;
@@ -226,7 +226,7 @@ sparc64_elf_reloc_type_lookup (abfd, cod
 
 static void
 sparc64_elf_info_to_howto (abfd, cache_ptr, dst)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *cache_ptr;
      Elf64_Internal_Rela *dst;
 {
@@ -240,7 +240,7 @@ sparc64_elf_info_to_howto (abfd, cache_p
    
 static long
 sparc64_elf_get_reloc_upper_bound (abfd, sec)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      asection *sec;
 {
   return (sec->reloc_count * 2 + 1) * sizeof (arelent *);
@@ -266,7 +266,6 @@ sparc64_elf_slurp_one_reloc_table (abfd,
      asymbol **symbols;
      boolean dynamic;
 {
-  struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
   PTR allocated = NULL;
   bfd_byte *native_relocs;
   arelent *relent;
@@ -501,7 +500,6 @@ sparc64_elf_write_relocs (abfd, sec, dat
   for (idx = 0; idx < sec->reloc_count; idx++)
     {
       bfd_vma addr;
-      unsigned int i;
 
       ++count;
 
@@ -723,13 +721,13 @@ sparc_elf_notsup_reloc (abfd,
 			input_section,
 			output_bfd,
 			error_message)
-     bfd *abfd;
-     arelent *reloc_entry;
-     asymbol *symbol;
-     PTR data;
-     asection *input_section;
-     bfd *output_bfd;
-     char **error_message;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry ATTRIBUTE_UNUSED;
+     asymbol *symbol ATTRIBUTE_UNUSED;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   return bfd_reloc_notsupported;
 }
@@ -745,7 +743,7 @@ sparc_elf_wdisp16_reloc (abfd, reloc_ent
      PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   bfd_vma relocation;
   bfd_vma insn;
@@ -783,7 +781,7 @@ sparc_elf_hix22_reloc (abfd,
      PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   bfd_vma relocation;
   bfd_vma insn;
@@ -820,7 +818,7 @@ sparc_elf_lox10_reloc (abfd,
      PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   bfd_vma relocation;
   bfd_vma insn;
@@ -1265,9 +1263,9 @@ sparc64_elf_add_symbol_hook (abfd, info,
      struct bfd_link_info *info;
      const Elf_Internal_Sym *sym;
      const char **namep;
-     flagword *flagsp;
-     asection **secp;
-     bfd_vma *valp;
+     flagword *flagsp ATTRIBUTE_UNUSED;
+     asection **secp ATTRIBUTE_UNUSED;
+     bfd_vma *valp ATTRIBUTE_UNUSED;
 {
   static char *stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
 
@@ -1387,7 +1385,7 @@ sparc64_elf_add_symbol_hook (abfd, info,
 
 static boolean
 sparc64_elf_output_arch_syms (output_bfd, info, finfo, func)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
      PTR finfo;
      boolean (*func) PARAMS ((PTR, const char *,
@@ -1460,7 +1458,7 @@ sparc64_elf_get_symbol_type (elf_sym, ty
 
 static void
 sparc64_elf_symbol_processing (abfd, asym)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      asymbol *asym;
 {
   elf_symbol_type *elfsym;
@@ -1898,7 +1896,7 @@ sparc64_elf_relocate_section (output_bfd
     {
       int r_type;
       reloc_howto_type *howto;
-      long r_symndx;
+      unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       Elf_Internal_Sym *sym;
       asection *sec;
@@ -2806,8 +2804,8 @@ sparc64_elf_merge_private_bfd_data (ibfd
 	  /* We don't want dynamic objects memory ordering and
 	     architecture to have any role. That's what dynamic linker
 	     should do.  */
-	  old_flags &= ~(EF_SPARCV9_MM | EF_SPARC_SUN_US1 | EF_SPARC_HAL_R1);
-	  old_flags |= (new_flags
+	  new_flags &= ~(EF_SPARCV9_MM | EF_SPARC_SUN_US1 | EF_SPARC_HAL_R1);
+	  new_flags |= (old_flags
 			& (EF_SPARCV9_MM
 			   | EF_SPARC_SUN_US1
 			   | EF_SPARC_HAL_R1));
@@ -2860,7 +2858,7 @@ sparc64_elf_merge_private_bfd_data (ibfd
 
 static const char *
 sparc64_elf_print_symbol_all (abfd, filep, symbol)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      PTR filep;
      asymbol *symbol;
 {
2000-05-25  Jakub Jelinek  <jakub@redhat.com>

	* elf64-sparc.c (sparc64_elf_relax_section): New.
	(sparc64_elf_relocate_section): Optimize tail call into branch always
	if possible.
	* elf32-sparc.c (elf32_sparc_relocate_section): Likewise.
	(elf32_sparc_relax_section): New.

--- bfd/elf64-sparc.c.jj	Thu Mar  9 12:01:37 2000
+++ bfd/elf64-sparc.c	Thu May 25 19:49:08 2000
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "sysdep.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "opcode/sparc.h"
 
 /* This is defined if one wants to build upward compatible binaries
    with the original sparc64-elf toolchain.  The support is kept in for
@@ -65,6 +66,8 @@ static void sparc64_elf_symbol_processin
 static boolean sparc64_elf_merge_private_bfd_data
   PARAMS ((bfd *, bfd *));
 
+static boolean sparc64_elf_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
 static boolean sparc64_elf_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
 	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -1853,6 +1856,22 @@ sparc64_elf_size_dynamic_sections (outpu
   return true;
 }
 
+#define SET_SEC_DO_RELAX(section) do { elf_section_data(section)->tdata = (void *)1; } while (0)
+#define SEC_DO_RELAX(section) (elf_section_data(section)->tdata == (void *)1)
+
+/*ARGSUSED*/
+static boolean
+sparc64_elf_relax_section (abfd, section, link_info, again)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *section ATTRIBUTE_UNUSED;
+     struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+     boolean *again;
+{
+  *again = false;
+  SET_SEC_DO_RELAX (section);
+  return true;
+}
+
 /* Relocate a SPARC64 ELF section.  */
 
 static boolean
@@ -2391,6 +2410,8 @@ sparc64_elf_relocate_section (output_bfd
 	  relocation = (splt->output_section->vma
 			+ splt->output_offset
 			+ sparc64_elf_plt_entry_offset (h->plt.offset));
+	  if (r_type == R_SPARC_WPLT30)
+	    goto do_wplt30;
 	  goto do_default;
 
 	case R_SPARC_OLO10:
@@ -2466,6 +2487,97 @@ sparc64_elf_relocate_section (output_bfd
 	  }
 	  break;
 
+	case R_SPARC_WDISP30:
+	do_wplt30:
+	  if (SEC_DO_RELAX (input_section)
+	      && rel->r_offset + 4 < input_section->_raw_size)
+	    {
+#define G0		0
+#define O7		15
+#define XCC		(2 << 20)
+#define COND(x)		(((x)&0xf)<<25)
+#define CONDA		COND(0x8)
+#define INSN_BPA	(F2(0,1) | CONDA | BPRED | XCC)
+#define INSN_BA		(F2(0,2) | CONDA)
+#define INSN_OR		F3(2, 0x2, 0)
+#define INSN_NOP	F2(0,4)
+
+	      bfd_vma x, y;
+
+	      /* If the instruction is a call with either:
+		 restore
+		 arithmetic instruction with rd == %o7
+		 where rs1 != %o7 and rs2 if it is register != %o7
+		 then we can optimize if the call destination is near
+		 by changing the call into a branch always.  */
+	      x = bfd_get_32 (input_bfd, contents + rel->r_offset);
+	      y = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+	      if ((x & OP(~0)) == OP(1) && (y & OP(~0)) == OP(2))
+		{
+		  if (((y & OP3(~0)) == OP3(0x3d) /* restore */
+		       || ((y & OP3(0x28)) == 0 /* arithmetic */
+			   && (y & RD(~0)) == RD(O7)))
+		      && (y & RS1(~0)) != RS1(O7)
+		      && ((y & F3I(~0))
+			  || (y & RS2(~0)) != RS2(O7)))
+		    {
+		      bfd_vma reloc;
+
+		      reloc = relocation + rel->r_addend - rel->r_offset;
+		      reloc -= (input_section->output_section->vma
+				+ input_section->output_offset);
+		      if (reloc & 3)
+			goto do_default;
+
+		      /* Ensure the branch fits into simm22.  */
+		      if ((reloc & ~(bfd_vma)0x7fffff)
+			   && ((reloc | 0x7fffff) != MINUS_ONE))
+			goto do_default;
+		      reloc >>= 2;
+
+		      /* Check whether it fits into simm19.  */
+		      if ((reloc & 0x3c0000) == 0
+			  || (reloc & 0x3c0000) == 0x3c0000)
+			x = INSN_BPA | (reloc & 0x7ffff); /* ba,pt %xcc */
+		      else
+			x = INSN_BA | (reloc & 0x3fffff); /* ba */
+		      bfd_put_32 (input_bfd, x, contents + rel->r_offset);
+		      r = bfd_reloc_ok;
+		      if (rel->r_offset >= 4
+			  && (y & (0xffffffff ^ RS1(~0)))
+			     == (INSN_OR | RD(O7) | RS2(G0)))
+			{
+			  bfd_vma z;
+			  unsigned int reg;
+
+			  z = bfd_get_32 (input_bfd,
+					  contents + rel->r_offset - 4);
+			  if ((z & (0xffffffff ^ RD(~0)))
+			      != (INSN_OR | RS1(O7) | RS2(G0)))
+			    break;
+
+			  /* The sequence was
+			     or %o7, %g0, %rN
+			     call foo
+			     or %rN, %g0, %o7
+
+			     If call foo was replaced with ba, replace
+			     or %rN, %g0, %o7 with nop.  */
+
+			  reg = (y & RS1(~0)) >> 14;
+			  if (reg != ((z & RD(~0)) >> 25)
+			      || reg == G0 || reg == O7)
+			    break;
+
+			  bfd_put_32 (input_bfd, INSN_NOP,
+				      contents + rel->r_offset + 4);
+			}
+		      break;
+		    }
+		}
+	    }
+	  /* FALLTHROUGH */
+
 	default:
 	do_default:
 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
@@ -2958,6 +3070,8 @@ const struct elf_size_info sparc64_elf_s
   sparc64_elf_canonicalize_dynamic_reloc
 #define bfd_elf64_bfd_reloc_type_lookup \
   sparc64_elf_reloc_type_lookup
+#define bfd_elf64_bfd_relax_section \
+  sparc64_elf_relax_section
 
 #define elf_backend_create_dynamic_sections \
   _bfd_elf_create_dynamic_sections
--- bfd/elf32-sparc.c.jj	Thu Mar  9 10:02:10 2000
+++ bfd/elf32-sparc.c	Thu May 25 19:48:56 2000
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/sparc.h"
+#include "opcode/sparc.h"
 
 static reloc_howto_type *elf32_sparc_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
@@ -36,6 +37,8 @@ static boolean elf32_sparc_adjust_dynami
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static boolean elf32_sparc_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf32_sparc_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
 static boolean elf32_sparc_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
 	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -1059,6 +1062,23 @@ elf32_sparc_size_dynamic_sections (outpu
   return true;
 }
 
+
+#define SET_SEC_DO_RELAX(section) do { elf_section_data(section)->tdata = (void *)1; } while (0)
+#define SEC_DO_RELAX(section) (elf_section_data(section)->tdata == (void *)1)
+
+/*ARGSUSED*/
+static boolean
+elf32_sparc_relax_section (abfd, section, link_info, again)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *section ATTRIBUTE_UNUSED;
+     struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+     boolean *again;
+{
+  *again = false;
+  SET_SEC_DO_RELAX (section);
+  return true;
+}
+
 /* Relocate a SPARC ELF section.  */
 
 static boolean
@@ -1515,6 +1535,7 @@ elf32_sparc_relocate_section (output_bfd
 	  break;
 	}
 
+      r = bfd_reloc_continue;
       if (r_type == R_SPARC_WDISP16)
 	{
 	  bfd_vma x;
@@ -1546,7 +1567,97 @@ elf32_sparc_relocate_section (output_bfd
 	  bfd_putl32 (/*input_bfd,*/ x, contents + rel->r_offset);
 	  r = bfd_reloc_ok;
 	}
-      else
+      else if ((r_type == R_SPARC_WDISP30 || r_type == R_SPARC_WPLT30)
+	       && SEC_DO_RELAX (input_section)
+	       && rel->r_offset + 4 < input_section->_raw_size)
+	{
+#define G0		0
+#define O7		15
+#define XCC		(2 << 20)
+#define COND(x)		(((x)&0xf)<<25)
+#define CONDA		COND(0x8)
+#define INSN_BPA	(F2(0,1) | CONDA | BPRED | XCC)
+#define INSN_BA		(F2(0,2) | CONDA)
+#define INSN_OR		F3(2, 0x2, 0)
+#define INSN_NOP	F2(0,4)
+
+	  bfd_vma x, y;
+
+	  /* If the instruction is a call with either:
+	     restore
+	     arithmetic instruction with rd == %o7
+	     where rs1 != %o7 and rs2 if it is register != %o7
+	     then we can optimize if the call destination is near
+	     by changing the call into a branch always.  */
+	  x = bfd_get_32 (input_bfd, contents + rel->r_offset);
+	  y = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+	  if ((x & OP(~0)) == OP(1) && (y & OP(~0)) == OP(2))
+	    {
+	      if (((y & OP3(~0)) == OP3(0x3d) /* restore */
+		   || ((y & OP3(0x28)) == 0 /* arithmetic */
+		       && (y & RD(~0)) == RD(O7)))
+		  && (y & RS1(~0)) != RS1(O7)
+		  && ((y & F3I(~0))
+		      || (y & RS2(~0)) != RS2(O7)))
+		{
+		  bfd_vma reloc;
+
+		  reloc = relocation + rel->r_addend - rel->r_offset;
+		  reloc -= (input_section->output_section->vma
+			   + input_section->output_offset);
+
+		  /* Ensure the reloc fits into simm22.  */
+		  if ((reloc & 3) == 0
+		      && ((reloc & ~(bfd_vma)0x7fffff) == 0
+			  || ((reloc | 0x7fffff) == ~(bfd_vma)0)))
+		    {
+		      reloc >>= 2;
+		
+		      /* Check whether it fits into simm19 on v9.  */
+		      if (((reloc & 0x3c0000) == 0
+			   || (reloc & 0x3c0000) == 0x3c0000)
+			  && (elf_elfheader (output_bfd)->e_flags & EF_SPARC_32PLUS))
+			x = INSN_BPA | (reloc & 0x7ffff); /* ba,pt %xcc */
+		      else
+			x = INSN_BA | (reloc & 0x3fffff); /* ba */
+		      bfd_put_32 (input_bfd, x, contents + rel->r_offset);
+		      r = bfd_reloc_ok;
+		      if (rel->r_offset >= 4
+			  && (y & (0xffffffff ^ RS1(~0)))
+			      == (INSN_OR | RD(O7) | RS2(G0)))
+			{
+			  bfd_vma z;
+			  unsigned int reg;
+
+			  z = bfd_get_32 (input_bfd,
+					  contents + rel->r_offset - 4);
+			  if ((z & (0xffffffff ^ RD(~0)))
+			      != (INSN_OR | RS1(O7) | RS2(G0)))
+			    break;
+
+			  /* The sequence was
+			     or %o7, %g0, %rN
+			     call foo
+			     or %rN, %g0, %o7
+
+			     If call foo was replaced with ba, replace
+			     or %rN, %g0, %o7 with nop.  */
+
+			  reg = (y & RS1(~0)) >> 14;
+			  if (reg != ((z & RD(~0)) >> 25)
+			      || reg == G0 || reg == O7)
+			    break;
+
+			  bfd_put_32 (input_bfd, INSN_NOP,
+				      contents + rel->r_offset + 4);
+			}
+
+		    }
+		}
+	    }
+	}
+
+      if (r == bfd_reloc_continue)
 	r = _bfd_final_link_relocate (howto, input_bfd, input_section,
 				      contents, rel->r_offset,
 				      relocation, rel->r_addend);
@@ -1964,6 +2075,7 @@ elf32_sparc_final_write_processing (abfd
 #define ELF_MAXPAGESIZE 0x10000
 
 #define bfd_elf32_bfd_reloc_type_lookup	elf32_sparc_reloc_type_lookup
+#define bfd_elf32_bfd_relax_section	elf32_sparc_relax_section
 #define elf_info_to_howto		elf32_sparc_info_to_howto
 #define elf_backend_create_dynamic_sections \
 					_bfd_elf_create_dynamic_sections
2000-05-25  Jakub Jelinek  <jakub@redhat.com>

	* config/tc-sparc.c (sparc_relax): New.
	(md_longopts): Add -relax and -no-relax options.
	(md_parse_options, md_show_usage): Likewise.
	(md_apply_fix3): Optimize tail call into branch always if possible.

--- gas/config/tc-sparc.c.jj	Thu May 18 13:13:53 2000
+++ gas/config/tc-sparc.c	Thu May 25 19:40:40 2000
@@ -91,6 +91,9 @@ static enum sparc_opcode_arch_val warn_a
    has been used in -64.  */
 static int no_undeclared_regs;
 
+/* Non-zero if we should try to relax jumps and calls.  */
+static int sparc_relax;
+
 /* Non-zero if we are generating PIC code.  */
 int sparc_pic_code;
 
@@ -415,6 +418,10 @@ struct option md_longopts[] = {
 #define OPTION_UNDECLARED_REGS (OPTION_MD_BASE + 13)
   {"undeclared-regs", no_argument, NULL, OPTION_UNDECLARED_REGS},
 #endif
+#define OPTION_RELAX (OPTION_MD_BASE + 14)
+  {"relax", no_argument, NULL, OPTION_RELAX},
+#define OPTION_NO_RELAX (OPTION_MD_BASE + 15)
+  {"no-relax", no_argument, NULL, OPTION_NO_RELAX},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof(md_longopts);
@@ -574,6 +581,14 @@ md_parse_option (c, arg)
       break;
 #endif
 
+    case OPTION_RELAX:
+      sparc_relax = 1;
+      break;
+
+    case OPTION_NO_RELAX:
+      sparc_relax = 0;
+      break;
+
     default:
       return 0;
     }
@@ -605,7 +620,9 @@ md_show_usage (stream)
 			specify variant of SPARC architecture\n\
 -bump			warn when assembler switches architectures\n\
 -sparc			ignored\n\
---enforce-aligned-data	force .long, etc., to be aligned correctly\n"));
+--enforce-aligned-data	force .long, etc., to be aligned correctly\n\
+-relax			relax jumps and branches (default)\n\
+-no-relax		avoid changing any jumps and branches\n"));
 #ifdef OBJ_AOUT
   fprintf (stream, _("\
 -k			generate PIC\n"));
@@ -2915,7 +2932,91 @@ md_apply_fix3 (fixP, value, segment)
 	      || fixP->fx_addsy == NULL
 	      || symbol_section_p (fixP->fx_addsy))
 	    ++val;
+
 	  insn |= val & 0x3fffffff;
+
+	  /* See if we have a delay slot */
+	  if (sparc_relax && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix)
+	    {
+#define G0		0
+#define O7		15
+#define XCC		(2 << 20)
+#define COND(x)		(((x)&0xf)<<25)
+#define CONDA		COND(0x8)
+#define INSN_BPA	(F2(0,1) | CONDA | BPRED | XCC)
+#define INSN_BA		(F2(0,2) | CONDA)
+#define INSN_OR		F3(2, 0x2, 0)
+#define INSN_NOP	F2(0,4)
+
+	      long delay;
+
+	      /* If the instruction is a call with either:
+		 restore
+		 arithmetic instruction with rd == %o7
+		 where rs1 != %o7 and rs2 if it is register != %o7
+		 then we can optimize if the call destination is near
+		 by changing the call into a branch always.  */
+	      if (INSN_BIG_ENDIAN)
+		delay = bfd_getb32 ((unsigned char *) buf + 4);
+	      else
+		delay = bfd_getl32 ((unsigned char *) buf + 4);
+	      if ((insn & OP(~0)) != OP(1) || (delay & OP(~0)) != OP(2))
+		break;
+	      if ((delay & OP3(~0)) != OP3(0x3d) /* restore */
+		  && ((delay & OP3(0x28)) != 0 /* arithmetic */
+		      || ((delay & RD(~0)) != RD(O7))))
+		break;
+	      if ((delay & RS1(~0)) == RS1(O7)
+		  || ((delay & F3I(~0)) == 0
+		      && (delay & RS2(~0)) == RS2(O7)))
+		break;
+	      /* Ensure the branch will fit into simm22.  */
+	      if ((val & 0x3fe00000)
+		  && (val & 0x3fe00000) != 0x3fe00000)
+		break;
+	      /* Check if the arch is v9 and branch will fit
+		 into simm19.  */
+	      if (((val & 0x3c0000) == 0
+		   || (val & 0x3c0000) == 0x3c0000)
+		  && (sparc_arch_size == 64
+		      || current_architecture >= SPARC_OPCODE_ARCH_V9))
+		/* ba,pt %xcc */
+		insn = INSN_BPA | (val & 0x7ffff);
+	      else
+		/* ba */
+		insn = INSN_BA | (val & 0x3fffff);
+	      if (fixP->fx_where >= 4
+		  && ((delay & (0xffffffff ^ RS1(~0)))
+		      == (INSN_OR | RD(O7) | RS2(G0))))
+		{
+		  long setter;
+		  int reg;
+
+		  if (INSN_BIG_ENDIAN)
+		    setter = bfd_getb32 ((unsigned char *) buf - 4);
+		  else
+		    setter = bfd_getl32 ((unsigned char *) buf - 4);
+		  if ((setter & (0xffffffff ^ RD(~0)))
+		       != (INSN_OR | RS1(O7) | RS2(G0)))
+		    break;
+		  /* The sequence was
+		     or %o7, %g0, %rN
+		     call foo
+		     or %rN, %g0, %o7
+
+		     If call foo was replaced with ba, replace
+		     or %rN, %g0, %o7 with nop.  */
+		  reg = (delay & RS1(~0)) >> 14;
+		  if (reg != ((setter & RD(~0)) >> 25)
+		      || reg == G0 || reg == O7)
+		    break;
+
+		  if (INSN_BIG_ENDIAN)
+		    bfd_putb32 (INSN_NOP, (unsigned char *) buf + 4);
+		  else
+		    bfd_putl32 (INSN_NOP, (unsigned char *) buf + 4);
+		}
+	    }
 	  break;
 
 	case BFD_RELOC_SPARC_11:

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