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]

relax jalr $t9 [R_MIPS_JALR symbol] to bal symbol


The idea of the optimization is to take advantage of the R_MIPS_JALR
relocations emitted by the n32 and n64 assemblers to avoid pipeline
stalls due to dependencies between the instruction that loads the
symbol address into $t9 and the jalr instruction, that, because of the
way GCC generates code, will generally be adjacent.  If symbol is
reachable with a branch, and it's not overridable, we replace the jump
with a branch.  The transformation is only enabled when the --relax
flag is passed to the linker.  Tested on mips64-linux-gnu.  Ok to
install?

Index: bfd/ChangeLog
from  Alexandre Oliva  <aoliva at redhat dot com>

	* elfxx-mips.c (_bfd_mips_relax_section): New function.
	* elfxx-mips.h (_bfd_mips_relax_section): Declare.
	* elfn32-mips.c, elf64-mips.c: Use it.

Index: bfd/elf64-mips.c
===================================================================
RCS file: /cvs/uberbaum/bfd/elf64-mips.c,v
retrieving revision 1.46
diff -u -p -r1.46 elf64-mips.c
--- bfd/elf64-mips.c 12 Mar 2003 23:05:51 -0000 1.46
+++ bfd/elf64-mips.c 24 Mar 2003 04:55:38 -0000
@@ -2887,6 +2887,7 @@ const struct elf_size_info mips_elf64_si
 #define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
 #define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
 #define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
+#define bfd_elf64_bfd_relax_section     _bfd_mips_relax_section
 
 /* MIPS ELF64 archive functions.  */
 #define bfd_elf64_archive_functions
Index: bfd/elfn32-mips.c
===================================================================
RCS file: /cvs/uberbaum/bfd/elfn32-mips.c,v
retrieving revision 1.8
diff -u -p -r1.8 elfn32-mips.c
--- bfd/elfn32-mips.c 12 Mar 2003 23:05:51 -0000 1.8
+++ bfd/elfn32-mips.c 24 Mar 2003 04:55:39 -0000
@@ -2211,6 +2211,7 @@ static const struct ecoff_debug_swap mip
 #define bfd_elf32_bfd_set_private_flags	_bfd_mips_elf_set_private_flags
 #define bfd_elf32_bfd_print_private_bfd_data \
 					_bfd_mips_elf_print_private_bfd_data
+#define bfd_elf32_bfd_relax_section     _bfd_mips_relax_section
 
 /* Support for SGI-ish mips targets using n32 ABI.  */
 
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/uberbaum/bfd/elfxx-mips.c,v
retrieving revision 1.46
diff -u -p -r1.46 elfxx-mips.c
--- bfd/elfxx-mips.c 12 Mar 2003 23:05:51 -0000 1.46
+++ bfd/elfxx-mips.c 24 Mar 2003 04:55:44 -0000
@@ -5451,6 +5451,197 @@ _bfd_mips_elf_check_relocs (abfd, info, 
   return TRUE;
 }
 
+bfd_boolean
+_bfd_mips_relax_section (abfd, sec, link_info, again)
+     bfd *abfd;
+     asection *sec;
+     struct bfd_link_info *link_info;
+     bfd_boolean *again;
+{
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Shdr *symtab_hdr;
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  size_t extsymoff;
+  bfd_boolean changed_contents = FALSE;
+  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
+  Elf_Internal_Sym *isymbuf = NULL;
+  unsigned long instruction = 0;
+
+  /* We are not currently changing any sizes, so only one pass.  */
+  *again = FALSE;
+
+  if (link_info->relocateable)
+    return TRUE;
+
+  internal_relocs = (MNAME(abfd,_bfd_elf,link_read_relocs)
+                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+                      link_info->keep_memory));
+  if (internal_relocs == NULL)
+    return TRUE;
+
+  irelend = internal_relocs + sec->reloc_count
+    * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
+
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      bfd_vma symval;
+      bfd_signed_vma sym_offset;
+      unsigned int r_type;
+      unsigned long r_symndx;
+      asection *sym_sec;
+
+      /* Turn jalr into bgezal, and jr into beq, if they're marked
+	 with a JALR relocation, that indicate where they jump to.
+	 This saves some pipeline bubbles.  */
+      r_type = ELF_R_TYPE (abfd, irel->r_info);
+      if (r_type != R_MIPS_JALR)
+	continue;
+
+      if (contents)
+	{
+	  instruction = bfd_get_32 (abfd, contents + irel->r_offset);
+	  /* if it's neither jalr nor jr, bail out.  */
+	  if ((instruction & 0xfc1fffff) != 0x0000f809
+	      && (instruction & 0xfc1fffff) != 0x00000008)
+	    continue;
+	}
+
+      r_symndx = ELF_R_SYM (abfd, irel->r_info);
+      /* Compute the address of the jump target.  */
+      if (r_symndx >= extsymoff)
+	{
+	  struct mips_elf_link_hash_entry *h
+	    = ((struct mips_elf_link_hash_entry *)
+	       elf_sym_hashes (abfd) [r_symndx - extsymoff]);
+
+	  while (h->root.root.type == bfd_link_hash_indirect
+		 || h->root.root.type == bfd_link_hash_warning)
+	    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+	  
+	  /* If a symbol is undefined, or if it may be overridden,
+	     skip it.  */
+	  if (! ((h->root.root.type == bfd_link_hash_defined
+		  || h->root.root.type == bfd_link_hash_defweak)
+		 && h->root.root.u.def.section)
+	      || (link_info->shared && ! link_info->symbolic
+		  && ! (h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)))
+	    continue;
+
+	  sym_sec = h->root.root.u.def.section;
+	  if (sym_sec->output_section)
+	    symval = (h->root.root.u.def.value
+		      + sym_sec->output_section->vma
+		      + sym_sec->output_offset);
+	  else
+	    symval = h->root.root.u.def.value;
+	}
+      else
+	{
+	  Elf_Internal_Sym *isym;
+
+	  /* Read this BFD's symbols if we haven't done so already.  */
+	  if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+	    {
+	      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+	      if (isymbuf == NULL)
+		isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+						symtab_hdr->sh_info, 0,
+						NULL, NULL, NULL);
+	      if (isymbuf == NULL)
+		goto relax_return;
+	    }
+
+	  isym = isymbuf + r_symndx;
+	  if (isym->st_shndx == SHN_UNDEF)
+	    continue;
+	  else if (isym->st_shndx == SHN_ABS)
+	    sym_sec = bfd_abs_section_ptr;
+	  else if (isym->st_shndx == SHN_COMMON)
+	    sym_sec = bfd_com_section_ptr;
+	  else
+	    sym_sec
+	      = bfd_section_from_elf_index (abfd, isym->st_shndx);
+	  symval = isym->st_value
+	    + sym_sec->output_section->vma
+	    + sym_sec->output_offset;
+	}
+
+      /* Compute branch offset, from delay slot of the jump to the
+	 branch target.  */
+      sym_offset = (symval + irel->r_addend)
+	- (sec_start + irel->r_offset + 4);
+
+      /* Branch offset must be properly aligned.  */
+      if ((sym_offset & 3) != 0)
+	continue;
+
+      sym_offset >>= 2;
+
+      /* Check that it's in range.  */
+      if (sym_offset < -0x8000 || sym_offset >= 0x8000)
+	continue;
+      
+      /* Get the section contents if we haven't done so already.  */
+      if (contents == NULL)
+	{
+	  /* Get cached copy if it exists.  */
+	  if (elf_section_data (sec)->this_hdr.contents != NULL)
+	    contents = elf_section_data (sec)->this_hdr.contents;
+	  else
+	    {
+	      contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+	      if (contents == NULL)
+		goto relax_return;
+
+	      free_contents = contents;
+	      if (! bfd_get_section_contents (abfd, sec, contents,
+					      (file_ptr) 0, sec->_raw_size))
+		goto relax_return;
+	    }
+
+	  /* Since we didn't have contents before, we hadn't checked
+	     whether we had the right instruction, so do it now.  */
+	  instruction = bfd_get_32 (abfd, contents + irel->r_offset);
+	  /* if it's neither jalr nor jr, bail out.  */
+	  if ((instruction & 0xfc1fffff) != 0x0000f809
+	      && (instruction & 0xfc1fffff) != 0x00000008)
+	    continue;
+	}
+
+      /* If it was jalr <reg>, turn it into bgezal $0, <target>.  */
+      if ((instruction & 0xfc1fffff) != 0x0000f809)
+	instruction = 0x10000000;
+      else if ((instruction & 0xfc1fffff) != 0x00000008)
+	instruction = 0x04110000;
+
+      instruction |= (sym_offset & 0xffff);
+      bfd_put_32 (abfd, instruction, contents + irel->r_offset);
+      changed_contents = TRUE;
+    }
+
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    {
+      if (!changed_contents && !link_info->keep_memory)
+        free (contents);
+      else
+        {
+          /* Cache the section contents for elf_link_input_bfd.  */
+          elf_section_data (sec)->this_hdr.contents = contents;
+        }
+    }
+  return TRUE;
+
+ relax_return:  
+  if (free_contents != NULL)
+    free (free_contents);
+  return FALSE;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
Index: bfd/elfxx-mips.h
===================================================================
RCS file: /cvs/uberbaum/bfd/elfxx-mips.h,v
retrieving revision 1.8
diff -u -p -r1.8 elfxx-mips.h
--- bfd/elfxx-mips.h 23 Jan 2003 11:51:33 -0000 1.8
+++ bfd/elfxx-mips.h 24 Mar 2003 04:55:44 -0000
@@ -108,3 +108,6 @@ extern bfd_reloc_status_type _bfd_mips_e
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 extern unsigned long _bfd_elf_mips_mach
   PARAMS ((flagword));
+extern bfd_boolean _bfd_mips_relax_section (bfd *, asection *,
+					    struct bfd_link_info *,
+					    bfd_boolean *);
Index: ld/testsuite/ChangeLog
from  Alexandre Oliva  <aoliva at redhat dot com>

	* ld-mips-elf/mips-elf.exp: Added...
	* ld-mips-elf/relax-jalr.s, ld-mips-elf/relax-jalr-n32.d,
	ld-mips-elf/relax-jalr-n32-shared.d, ld-mips-elf/relax-jalr-n64.d,
	ld-mips-elf/relax-jalr-n64-shared.d: New tests.

Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
RCS file: /cvs/uberbaum/ld/testsuite/ld-mips-elf/mips-elf.exp,v
retrieving revision 1.9
diff -u -p -r1.9 mips-elf.exp
--- ld/testsuite/ld-mips-elf/mips-elf.exp 11 Mar 2003 19:20:16 -0000 1.9
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 24 Mar 2003 04:55:46 -0000
@@ -33,6 +33,11 @@ if { [istarget mips*-*-*] } then {
 
 	# Test multi-got link.
 	run_dump_test "multi-got-1"
+ 
+	run_dump_test "relax-jalr-n32"
+	run_dump_test "relax-jalr-n32-shared"
+	run_dump_test "relax-jalr-n64"
+	run_dump_test "relax-jalr-n64-shared"
     }
 
     if { $linux_gnu } {
Index: ld/testsuite/ld-mips-elf/relax-jalr-n32-shared.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/relax-jalr-n32-shared.d
diff -N ld/testsuite/ld-mips-elf/relax-jalr-n32-shared.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/relax-jalr-n32-shared.d 24 Mar 2003 04:55:46 -0000
@@ -0,0 +1,23 @@
+#name: MIPS relax-jalr-shared n32
+#source: relax-jalr.s
+#as: -KPIC -n32
+#objdump: --prefix-addresses -d --show-raw-insn
+#ld: --relax -shared -melf32btsmipn32
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+	\.\.\.
+.*	lw	t9,.*
+.*	jalr	t9
+.*	nop
+	\.\.\.
+.*	lw	t9,.*
+.*	jalr	t9
+.*	nop
+	\.\.\.
+.*	lw	t9,.*
+.*	bal	.* <__start>
+.*	nop
+	\.\.\.
Index: ld/testsuite/ld-mips-elf/relax-jalr-n32.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/relax-jalr-n32.d
diff -N ld/testsuite/ld-mips-elf/relax-jalr-n32.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/relax-jalr-n32.d 24 Mar 2003 04:55:46 -0000
@@ -0,0 +1,23 @@
+#name: MIPS relax-jalr n32
+#source: relax-jalr.s
+#as: -KPIC -n32
+#objdump: --prefix-addresses -d --show-raw-insn
+#ld: --relax -melf32btsmipn32
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+	\.\.\.
+.*	lw	t9,.*
+.*	bal	.* <__start>
+.*	nop
+	\.\.\.
+.*	lw	t9,.*
+.*	bal	.* <__start>
+.*	nop
+	\.\.\.
+.*	lw	t9,.*
+.*	bal	.* <__start>
+.*	nop
+.*	nop
Index: ld/testsuite/ld-mips-elf/relax-jalr-n64-shared.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/relax-jalr-n64-shared.d
diff -N ld/testsuite/ld-mips-elf/relax-jalr-n64-shared.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/relax-jalr-n64-shared.d 24 Mar 2003 04:55:46 -0000
@@ -0,0 +1,25 @@
+#name: MIPS relax-jalr-shared n64
+#source: relax-jalr.s
+#as: -KPIC -64
+#objdump: --prefix-addresses -d --show-raw-insn
+#ld: --relax -shared -melf64btsmip
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+	\.\.\.
+.*	ld	t9,.*
+.*	jalr	t9
+.*	nop
+	\.\.\.
+.*	ld	t9,.*
+.*	jalr	t9
+.*	nop
+	\.\.\.
+.*	ld	t9,.*
+.*	bal	.* <__start>
+.*	nop
+.*	nop
+Disassembly of section \.MIPS\.stubs:
+	\.\.\.
Index: ld/testsuite/ld-mips-elf/relax-jalr-n64.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/relax-jalr-n64.d
diff -N ld/testsuite/ld-mips-elf/relax-jalr-n64.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/relax-jalr-n64.d 24 Mar 2003 04:55:46 -0000
@@ -0,0 +1,23 @@
+#name: MIPS relax-jalr n64
+#source: relax-jalr.s
+#as: -KPIC -64
+#objdump: --prefix-addresses -d --show-raw-insn
+#ld: --relax -melf64btsmip
+
+.*:     file format elf.*mips.*
+
+Disassembly of section \.text:
+	\.\.\.
+	\.\.\.
+.*	ld	t9,.*
+.*	bal	.* <__start>
+.*	nop
+	\.\.\.
+.*	ld	t9,.*
+.*	bal	.* <__start>
+.*	nop
+	\.\.\.
+.*	ld	t9,.*
+.*	bal	.* <__start>
+.*	nop
+.*	nop
Index: ld/testsuite/ld-mips-elf/relax-jalr.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/relax-jalr.s
diff -N ld/testsuite/ld-mips-elf/relax-jalr.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/relax-jalr.s 24 Mar 2003 04:55:46 -0000
@@ -0,0 +1,12 @@
+.globl __start
+	.space 8
+.ent __start
+__start:
+.Lstart:
+	.space 16
+        jal __start
+	.space 32
+        jal __start
+	.space 64
+	jal .Lstart
+.end __start
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva at {redhat dot com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva at {lsd dot ic dot unicamp dot br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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