From aba6bc71dd8b4f9944bc4c7f4cf73f58f7960595 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 7 Dec 2012 00:03:18 +0000 Subject: [PATCH] * options.h (General_options): Add no_toc_optimize. * powerpc.cc (ok_lo_toc_insn): New function. (Target_powerpc::Relocate::relocate): Optimize toc access sequences. --- gold/ChangeLog | 6 ++++ gold/options.h | 3 ++ gold/powerpc.cc | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/gold/ChangeLog b/gold/ChangeLog index 53be4b6a03c..25898c59c3b 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,9 @@ +2012-12-07 Alan Modra + + * 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 * options.h (General_options): Add plt_align, plt_static_chain, diff --git a/gold/options.h b/gold/options.h index 216620a8068..1a25b7b070d 100644 --- a/gold/options.h +++ b/gold/options.h @@ -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")); diff --git a/gold/powerpc.cc b/gold/powerpc.cc index a5c6b38f64a..7fa68d771de 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -5441,6 +5441,33 @@ Target_powerpc::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 @@ -6021,6 +6048,75 @@ Target_powerpc::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(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(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) { -- 2.30.2