* options.h (General_options): Add no_toc_optimize.
* powerpc.cc (ok_lo_toc_insn): New function. (Target_powerpc::Relocate::relocate): Optimize toc access sequences.
This commit is contained in:
parent
9cb2f5a93d
commit
aba6bc71dd
3 changed files with 105 additions and 0 deletions
|
@ -1,3 +1,9 @@
|
|||
2012-12-07 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* options.h (General_options): Add no_toc_optimize.
|
||||
* powerpc.cc (ok_lo_toc_insn): New function.
|
||||
(Target_powerpc::Relocate::relocate): Optimize toc access sequences.
|
||||
|
||||
2012-12-06 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* options.h (General_options): Add plt_align, plt_static_chain,
|
||||
|
|
|
@ -1109,6 +1109,9 @@ class General_options
|
|||
DEFINE_uint64(Ttext, options::ONE_DASH, '\0', -1U,
|
||||
N_("Set the address of the text segment"), N_("ADDRESS"));
|
||||
|
||||
DEFINE_bool(no_toc_optimize, options::TWO_DASHES, '\0', false,
|
||||
N_("(PowerPC64 only) Don't optimize TOC code sequences"), NULL);
|
||||
|
||||
DEFINE_set(undefined, options::TWO_DASHES, 'u',
|
||||
N_("Create undefined reference to SYMBOL"), N_("SYMBOL"));
|
||||
|
||||
|
|
|
@ -5441,6 +5441,33 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
|
|||
this->copy_relocs_.emit(this->rela_dyn_section(layout));
|
||||
}
|
||||
|
||||
// Return TRUE iff INSN is one we expect on a _LO variety toc/got
|
||||
// reloc.
|
||||
|
||||
static bool
|
||||
ok_lo_toc_insn(uint32_t insn)
|
||||
{
|
||||
return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
|
||||
|| (insn & (0x3f << 26)) == 32u << 26 /* lwz */
|
||||
|| (insn & (0x3f << 26)) == 34u << 26 /* lbz */
|
||||
|| (insn & (0x3f << 26)) == 36u << 26 /* stw */
|
||||
|| (insn & (0x3f << 26)) == 38u << 26 /* stb */
|
||||
|| (insn & (0x3f << 26)) == 40u << 26 /* lhz */
|
||||
|| (insn & (0x3f << 26)) == 42u << 26 /* lha */
|
||||
|| (insn & (0x3f << 26)) == 44u << 26 /* sth */
|
||||
|| (insn & (0x3f << 26)) == 46u << 26 /* lmw */
|
||||
|| (insn & (0x3f << 26)) == 47u << 26 /* stmw */
|
||||
|| (insn & (0x3f << 26)) == 48u << 26 /* lfs */
|
||||
|| (insn & (0x3f << 26)) == 50u << 26 /* lfd */
|
||||
|| (insn & (0x3f << 26)) == 52u << 26 /* stfs */
|
||||
|| (insn & (0x3f << 26)) == 54u << 26 /* stfd */
|
||||
|| ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
|
||||
&& (insn & 3) != 1)
|
||||
|| ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
|
||||
&& ((insn & 3) == 0 || (insn & 3) == 3))
|
||||
|| (insn & (0x3f << 26)) == 12u << 26 /* addic */);
|
||||
}
|
||||
|
||||
// Return the value to use for a branch relocation.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
@ -6021,6 +6048,75 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
|||
break;
|
||||
}
|
||||
|
||||
if (size == 64)
|
||||
{
|
||||
// Multi-instruction sequences that access the TOC can be
|
||||
// optimized, eg. addis ra,r2,0; addi rb,ra,x;
|
||||
// to nop; addi rb,r2,x;
|
||||
switch (r_type)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
|
||||
case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
|
||||
case elfcpp::R_POWERPC_GOT_TPREL16_HA:
|
||||
case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
|
||||
case elfcpp::R_POWERPC_GOT16_HA:
|
||||
case elfcpp::R_PPC64_TOC16_HA:
|
||||
if (!parameters->options().no_toc_optimize())
|
||||
{
|
||||
Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
|
||||
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
|
||||
if ((insn & ((0x3f << 26) | 0x1f << 16))
|
||||
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
|
||||
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||
_("toc optimization is not supported "
|
||||
"for %#08x instruction"), insn);
|
||||
else if (value + 0x8000 < 0x10000)
|
||||
{
|
||||
elfcpp::Swap<32, big_endian>::writeval(iview, nop);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_POWERPC_GOT_TLSLD16_LO:
|
||||
case elfcpp::R_POWERPC_GOT_TLSGD16_LO:
|
||||
case elfcpp::R_POWERPC_GOT_TPREL16_LO:
|
||||
case elfcpp::R_POWERPC_GOT_DTPREL16_LO:
|
||||
case elfcpp::R_POWERPC_GOT16_LO:
|
||||
case elfcpp::R_PPC64_GOT16_LO_DS:
|
||||
case elfcpp::R_PPC64_TOC16_LO:
|
||||
case elfcpp::R_PPC64_TOC16_LO_DS:
|
||||
if (!parameters->options().no_toc_optimize())
|
||||
{
|
||||
Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
|
||||
Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
|
||||
if (!ok_lo_toc_insn(insn))
|
||||
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||
_("toc optimization is not supported "
|
||||
"for %#08x instruction"), insn);
|
||||
else if (value + 0x8000 < 0x10000)
|
||||
{
|
||||
if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
|
||||
{
|
||||
// Transform addic to addi when we change reg.
|
||||
insn &= ~((0x3f << 26) | (0x1f << 16));
|
||||
insn |= (14u << 26) | (2 << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn &= ~(0x1f << 16);
|
||||
insn |= 2 << 16;
|
||||
}
|
||||
elfcpp::Swap<32, big_endian>::writeval(iview, insn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
typename Reloc::Overflow_check overflow = Reloc::CHECK_NONE;
|
||||
switch (r_type)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue