From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7803) id 01F433857356; Fri, 21 Apr 2023 07:49:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 01F433857356 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Nelson Chu To: bfd-cvs@sourceware.org Subject: [binutils-gdb] RISC-V: Optimize relaxation of gp with max_alignment. X-Act-Checkin: binutils-gdb X-Git-Author: Lifang Xia X-Git-Refname: refs/heads/master X-Git-Oldrev: 3a117c5887312afb3f1567f1cae3316872d575f4 X-Git-Newrev: 0699f2d795cdb4bc4db2bcf438291ec09d21f0da Message-Id: <20230421074919.01F433857356@sourceware.org> Date: Fri, 21 Apr 2023 07:49:19 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Apr 2023 07:49:19 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D0699f2d795cd= b4bc4db2bcf438291ec09d21f0da commit 0699f2d795cdb4bc4db2bcf438291ec09d21f0da Author: Lifang Xia Date: Thu Oct 27 11:19:15 2022 +0800 RISC-V: Optimize relaxation of gp with max_alignment. =20 This should be the first related issue, which posted in riscv-gnu-toolc= hain, https://github.com/riscv-collab/riscv-gnu-toolchain/issues/497 =20 If the output sections are not between gp and the symbol, then their al= ignments shouldn't affect the gp relaxation. However, this patch improves this = idea even more, it limits the range to the gp+-2k, which means only the outp= ut section which are in the [gp-2K, gp+2K) range need to be considered. =20 Even if the output section candidates may be different for each relax p= asses, the symbol that can be relaxed ar this round will not be truncated at n= ext round. That is because this round you can do relaxation which means th= at the section where the symbol is located is within the [gp-2K, gp+2K) range,= so all the output section alignments between them should be considered. In ot= her words, if the alignments between them may cause truncated, then we shou= ld already preserve the size and won't do the gp relaxation this time. =20 This patch can resolve the github issue which mentioned above, and also= passed all gcc/binutils regressions of riscv-gnu-toolchain, so should be worth= and safe enough to commit. =20 Originally, this patch also do the same optimization for the call relax= ations, https://sourceware.org/pipermail/binutils/2022-October/123918.html But just in case there is something that has not been considered, we on= ly deal with the gp relaxation at this time. =20 bfd/ * elfnn-riscv.c (riscv_elf_link_hash_table): Added new bfd_vma, max_alignment_for_gp. It is used to record the maximum alignme= nt of the output sections, which are in the [gp-2K, gp+2k) range. (riscv_elf_link_hash_table_create): Init max_alignment_for_gp t= o -1. (_bfd_riscv_get_max_alignment): Added new parameter, gp. If gp= is zero, then all the output section alignments are possible candi= dates; Otherwise, only the output sections which are in the [gp-2K, gp= +2K) range need to be considered. (_bfd_riscv_relax_lui): Called _bfd_riscv_get_max_alignment wit= h the non-zero gp if the max_alignment_for_gp is -1. (_bfd_riscv_relax_pc): Likewise. (_bfd_riscv_relax_section): Record the first input section, so = that we can reset the max_alignment_for_gp for each repeated relax p= asses. ld/ * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated. * testsuite/ld-riscv-elf/relax-max-align-gp.*: New testcase. I= t fails without this patch. Diff: --- bfd/elfnn-riscv.c | 103 ++++++++++++++++++---= ---- ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 1 + ld/testsuite/ld-riscv-elf/relax-max-align-gp.d | 46 +++++++++++ ld/testsuite/ld-riscv-elf/relax-max-align-gp.s | 28 +++++++ 4 files changed, 149 insertions(+), 29 deletions(-) diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 0dd9b27c8ae..e90e36b58bb 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -200,6 +200,9 @@ struct riscv_elf_link_hash_table /* The max alignment of output sections. */ bfd_vma max_alignment; =20 + /* The max alignment of output sections in [gp-2K, gp+2K) range. */ + bfd_vma max_alignment_for_gp; + /* Used by local STT_GNU_IFUNC symbols. */ htab_t loc_hash_table; void * loc_hash_memory; @@ -488,6 +491,7 @@ riscv_elf_link_hash_table_create (bfd *abfd) } =20 ret->max_alignment =3D (bfd_vma) -1; + ret->max_alignment_for_gp =3D (bfd_vma) -1; =20 /* Create hash table for local ifunc. */ ret->loc_hash_table =3D htab_try_create (1024, @@ -4460,17 +4464,27 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, as= ection *sym_sec, link_info, pcgp_relocs, rel + 1); } =20 -/* Traverse all output sections and return the max alignment. */ +/* Traverse all output sections and return the max alignment. + + If gp is zero, then all the output section alignments are + possible candidates; Otherwise, only the output sections + which are in the [gp-2K, gp+2K) range need to be considered. */ =20 static bfd_vma -_bfd_riscv_get_max_alignment (asection *sec) +_bfd_riscv_get_max_alignment (asection *sec, bfd_vma gp) { unsigned int max_alignment_power =3D 0; asection *o; =20 for (o =3D sec->output_section->owner->sections; o !=3D NULL; o =3D o->n= ext) { - if (o->alignment_power > max_alignment_power) + bool valid =3D true; + if (gp + && !(VALID_ITYPE_IMM (sec_addr (o) - gp) + || VALID_ITYPE_IMM (sec_addr (o) + o->size - gp))) + valid =3D false; + + if (valid && o->alignment_power > max_alignment_power) max_alignment_power =3D o->alignment_power; } =20 @@ -4492,15 +4506,16 @@ _bfd_riscv_relax_lui (bfd *abfd, riscv_pcgp_relocs *pcgp_relocs, bool undefined_weak) { + struct riscv_elf_link_hash_table *htab =3D riscv_elf_hash_table (link_in= fo); bfd_byte *contents =3D elf_section_data (sec)->this_hdr.contents; - bfd_vma gp =3D riscv_elf_hash_table (link_info)->params->relax_gp - ? riscv_global_pointer_value (link_info) - : 0; + bfd_vma gp =3D htab->params->relax_gp + ? riscv_global_pointer_value (link_info) + : 0; int use_rvc =3D elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; =20 BFD_ASSERT (rel->r_offset + 4 <=3D sec->size); =20 - if (gp) + if (!undefined_weak && gp) { /* If gp and the symbol are in the same output section, which is not= the abs section, then consider only that output section's alignment. */ @@ -4510,16 +4525,28 @@ _bfd_riscv_relax_lui (bfd *abfd, if (h->u.def.section->output_section =3D=3D sym_sec->output_section && sym_sec->output_section !=3D bfd_abs_section_ptr) max_alignment =3D (bfd_vma) 1 << sym_sec->output_section->alignment_power; + else + { + /* Consider output section alignments which are in [gp-2K, gp+2K). */ + max_alignment =3D htab->max_alignment_for_gp; + if (max_alignment =3D=3D (bfd_vma) -1) + { + max_alignment =3D _bfd_riscv_get_max_alignment (sec, gp); + htab->max_alignment_for_gp =3D max_alignment; + } + } } =20 /* Is the reference in range of x0 or gp? - Valid gp range conservatively because of alignment issue. */ + Valid gp range conservatively because of alignment issue. + + Should we also consider the alignment issue for x0 base? */ if (undefined_weak - || (VALID_ITYPE_IMM (symval) - || (symval >=3D gp - && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) - || (symval < gp - && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))) + || VALID_ITYPE_IMM (symval) + || (symval >=3D gp + && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) + || (symval < gp + && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))) { unsigned sym =3D ELFNN_R_SYM (rel->r_info); switch (ELFNN_R_TYPE (rel->r_info)) @@ -4709,6 +4736,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, riscv_pcgp_relocs *pcgp_relocs, bool undefined_weak) { + struct riscv_elf_link_hash_table *htab =3D riscv_elf_hash_table (link_in= fo); bfd_byte *contents =3D elf_section_data (sec)->this_hdr.contents; bfd_vma gp =3D riscv_global_pointer_value (link_info); =20 @@ -4765,7 +4793,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, abort (); } =20 - if (gp) + if (!undefined_weak && gp) { /* If gp and the symbol are in the same output section, which is not= the abs section, then consider only that output section's alignment. */ @@ -4775,16 +4803,28 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, if (h->u.def.section->output_section =3D=3D sym_sec->output_section && sym_sec->output_section !=3D bfd_abs_section_ptr) max_alignment =3D (bfd_vma) 1 << sym_sec->output_section->alignment_power; + else + { + /* Consider output section alignments which are in [gp-2K, gp+2K). */ + max_alignment =3D htab->max_alignment_for_gp; + if (max_alignment =3D=3D (bfd_vma) -1) + { + max_alignment =3D _bfd_riscv_get_max_alignment (sec, gp); + htab->max_alignment_for_gp =3D max_alignment; + } + } } =20 /* Is the reference in range of x0 or gp? - Valid gp range conservatively because of alignment issue. */ + Valid gp range conservatively because of alignment issue. + + Should we also consider the alignment issue for x0 base? */ if (undefined_weak - || (VALID_ITYPE_IMM (symval) - || (symval >=3D gp - && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) - || (symval < gp - && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))) + || VALID_ITYPE_IMM (symval) + || (symval >=3D gp + && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size)) + || (symval < gp + && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))) { unsigned sym =3D hi_reloc.hi_sym; switch (ELFNN_R_TYPE (rel->r_info)) @@ -4877,6 +4917,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, unsigned int i; bfd_vma max_alignment, reserve_size =3D 0; riscv_pcgp_relocs pcgp_relocs; + static asection *first_section =3D NULL; =20 *again =3D false; =20 @@ -4892,6 +4933,13 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, || *(htab->data_segment_phase) =3D=3D 4) return true; =20 + /* Record the first relax section, so that we can reset the + max_alignment_for_gp for the repeated relax passes. */ + if (first_section =3D=3D NULL) + first_section =3D sec; + else if (first_section =3D=3D sec) + htab->max_alignment_for_gp =3D -1; + riscv_init_pcgp_relocs (&pcgp_relocs); =20 /* Read this BFD's relocs if we haven't done so already. */ @@ -4901,17 +4949,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, info->keep_memory))) goto fail; =20 - if (htab) + /* Estimate the maximum alignment for all output sections once time + should be enough. */ + max_alignment =3D htab->max_alignment; + if (max_alignment =3D=3D (bfd_vma) -1) { - max_alignment =3D htab->max_alignment; - if (max_alignment =3D=3D (bfd_vma) -1) - { - max_alignment =3D _bfd_riscv_get_max_alignment (sec); - htab->max_alignment =3D max_alignment; - } + max_alignment =3D _bfd_riscv_get_max_alignment (sec, 0/* gp */); + htab->max_alignment =3D max_alignment; } - else - max_alignment =3D _bfd_riscv_get_max_alignment (sec); =20 /* Examine and consider relaxing each reloc. */ for (i =3D 0; i < sec->reloc_count; i++) diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-r= iscv-elf/ld-riscv-elf.exp index 43572c5286b..9e103b283f7 100644 --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp @@ -171,6 +171,7 @@ if [istarget "riscv*-*-*"] { run_dump_test "attr-merge-priv-spec-failed-05" run_dump_test "attr-merge-priv-spec-failed-06" run_dump_test "attr-phdr" + run_dump_test "relax-max-align-gp" run_ld_link_tests [list \ [list "Weak reference 32" "-T weakref.ld -m[riscv_choose_ilp32_emul]" "" \ "-march=3Drv32i -mabi=3Dilp32" {weakref32.s} \ diff --git a/ld/testsuite/ld-riscv-elf/relax-max-align-gp.d b/ld/testsuite/= ld-riscv-elf/relax-max-align-gp.d new file mode 100644 index 00000000000..637de426ee4 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/relax-max-align-gp.d @@ -0,0 +1,46 @@ +#source: relax-max-align-gp.s +#ld: +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +0+[0-9a-f]+ <_start>: +.*:[ ]+[0-9a-f]+[ ]+add[ ]+.* +.*:[ ]+[0-9a-f]+[ ]+jal[ ]+.* +.*:[ ]+[0-9a-f]+[ ]+j[ ]+.* +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop +.*:[ ]+[0-9a-f]+[ ]+nop + +0+[0-9a-f]+ : +.*:[ ]+[0-9a-f]+[ ]+ret +[ ]+... diff --git a/ld/testsuite/ld-riscv-elf/relax-max-align-gp.s b/ld/testsuite/= ld-riscv-elf/relax-max-align-gp.s new file mode 100644 index 00000000000..ce3da21e7f4 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/relax-max-align-gp.s @@ -0,0 +1,28 @@ + +.global _start +_start: + lui a0, %hi(gdata) + addi a0, a0, %lo(gdata) + call func + j . + .size _start, . - _start + +.global func +.align 7 +func: + ret + .size func, . - func + +.data +padding: + .long 0 + .long 0 + .long 0 + .long 0 + .size padding, . - padding + +.global gdata +.type gdata, object +gdata: + .zero 4 + .size gdata, . - gdata