* 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.
This commit is contained in:
parent
6c08d69728
commit
f7775d95e6
@ -1,3 +1,11 @@
|
||||
2000-05-26 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.
|
||||
|
||||
2000-05-26 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf64-sparc.c: Add ATTRIBUTE_UNUSED to unused function parameters.
|
||||
|
@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
#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_dynamic_symbol
|
||||
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 (output_bfd, info)
|
||||
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
|
||||
@ -1518,6 +1538,7 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
|
||||
break;
|
||||
}
|
||||
|
||||
r = bfd_reloc_continue;
|
||||
if (r_type == R_SPARC_WDISP16)
|
||||
{
|
||||
bfd_vma x;
|
||||
@ -1549,7 +1570,97 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section,
|
||||
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);
|
||||
@ -1967,6 +2078,7 @@ elf32_sparc_final_write_processing (abfd, linker)
|
||||
#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
|
||||
|
@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
#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_processing
|
||||
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 (output_bfd, info)
|
||||
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
|
||||
@ -2394,6 +2413,8 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
||||
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:
|
||||
@ -2469,6 +2490,97 @@ sparc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
||||
}
|
||||
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,
|
||||
@ -2961,6 +3073,8 @@ const struct elf_size_info sparc64_elf_size_info =
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user