RISC-V: Optimize lui and auipc relaxations for undefweak symbol.
authorJim Wilson <jimw@sifive.com>
Fri, 20 Sep 2019 22:01:20 +0000 (15:01 -0700)
committerJim Wilson <jimw@sifive.com>
Fri, 20 Sep 2019 22:01:20 +0000 (15:01 -0700)
For the lui and auipc relaxations, since the symbol value of an undefined weak
symbol is always be zero, we can optimize the patterns into a single LI/MV/ADDI
instruction.

bfd/
* elfnn-riscv.c (riscv_pcgp_hi_reloc): Add new field undefined_weak.
(riscv_record_pcgp_hi_reloc): New parameter undefined_weak.
Set undefined_weak field from it.
(relax_func_t): New parameter undefined_weak.
(_bfd_riscv_relax_call): New ignored parameter undefined_weak.
(_bfd_riscv_relax_tls_le): Likewise.
(_bfd_riscv_relax_align): Likewise.
(_bfd_riscv_relax_delete): Likewise.
(_bfd_riscv_relax_lui): New parameter undefined_weak.  If true,
allow relaxing.  For LO12* relocs, set rs1 to x0 when undefined_weak.
(_bfd_riscv_relax_pc): New parameter undefined_weak.  For LO12* relocs,
set undefined_weak from hi_reloc.  If true, allow relaxing.  For LO12*
relocs, set rs1 to x0 when undefined_weak and change to non-pcrel
reloc.
(_bfd_riscv_relax_section): New local undefined_weak.  Set for
undef weak relocs that can be relaxed.  Pass to relax_func call.

ld/
* testsuite/ld-riscv-elf/weakref32.s: Add relaxable undef weak code.
* testsuite/ld-riscv-elf/weakref64.s: Likewise.
* testsuite/ld-riscv-elf/weakref32.d: Updated.
* testsuite/ld-riscv-elf/weakref64.d: Updated.

bfd/ChangeLog
bfd/elfnn-riscv.c
ld/ChangeLog
ld/testsuite/ld-riscv-elf/weakref32.d
ld/testsuite/ld-riscv-elf/weakref32.s
ld/testsuite/ld-riscv-elf/weakref64.d
ld/testsuite/ld-riscv-elf/weakref64.s

index 080c628feeb047f456303e57634ca362e3414ad8..b1a4aebd214810864649298156370141de401ca3 100644 (file)
@@ -1,3 +1,22 @@
+2019-09-20  Nelson Chu <nelson.chu@sifive.com>
+
+       * elfnn-riscv.c (riscv_pcgp_hi_reloc): Add new field undefined_weak.
+       (riscv_record_pcgp_hi_reloc): New parameter undefined_weak.
+       Set undefined_weak field from it.
+       (relax_func_t): New parameter undefined_weak.
+       (_bfd_riscv_relax_call): New ignored parameter undefined_weak.
+       (_bfd_riscv_relax_tls_le): Likewise.
+       (_bfd_riscv_relax_align): Likewise.
+       (_bfd_riscv_relax_delete): Likewise.
+       (_bfd_riscv_relax_lui): New parameter undefined_weak.  If true,
+       allow relaxing.  For LO12* relocs, set rs1 to x0 when undefined_weak.
+       (_bfd_riscv_relax_pc): New parameter undefined_weak.  For LO12* relocs,
+       set undefined_weak from hi_reloc.  If true, allow relaxing.  For LO12*
+       relocs, set rs1 to x0 when undefined_weak and change to non-pcrel
+       reloc.
+       (_bfd_riscv_relax_section): New local undefined_weak.  Set for
+       undef weak relocs that can be relaxed.  Pass to relax_func call.
+
 2019-09-20  Alan Modra  <amodra@gmail.com>
 
        * bfd-in.h (bfd_section_name, bfd_section_size, bfd_section_vma),
index ccf904af1bcc8c339f02945f8cfbac7f20ad7a88..4ffe6a36e68f6c6c8e2301627dceedfef908f2db 100644 (file)
@@ -3319,6 +3319,7 @@ struct riscv_pcgp_hi_reloc
   bfd_vma hi_addr;
   unsigned hi_sym;
   asection *sym_sec;
+  bfd_boolean undefined_weak;
   riscv_pcgp_hi_reloc *next;
 };
 
@@ -3377,7 +3378,8 @@ riscv_free_pcgp_relocs (riscv_pcgp_relocs *p,
 static bfd_boolean
 riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off,
                            bfd_vma hi_addend, bfd_vma hi_addr,
-                           unsigned hi_sym, asection *sym_sec)
+                           unsigned hi_sym, asection *sym_sec,
+                           bfd_boolean undefined_weak)
 {
   riscv_pcgp_hi_reloc *new = bfd_malloc (sizeof(*new));
   if (!new)
@@ -3387,6 +3389,7 @@ riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off,
   new->hi_addr = hi_addr;
   new->hi_sym = hi_sym;
   new->sym_sec = sym_sec;
+  new->undefined_weak = undefined_weak;
   new->next = p->hi;
   p->hi = new;
   return TRUE;
@@ -3439,7 +3442,8 @@ typedef bfd_boolean (*relax_func_t) (bfd *, asection *, asection *,
                                     struct bfd_link_info *,
                                     Elf_Internal_Rela *,
                                     bfd_vma, bfd_vma, bfd_vma, bfd_boolean *,
-                                    riscv_pcgp_relocs *);
+                                    riscv_pcgp_relocs *,
+                                    bfd_boolean undefined_weak);
 
 /* Relax AUIPC + JALR into JAL.  */
 
@@ -3451,7 +3455,8 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
                       bfd_vma max_alignment,
                       bfd_vma reserve_size ATTRIBUTE_UNUSED,
                       bfd_boolean *again,
-                      riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED)
+                      riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
+                      bfd_boolean undefined_weak ATTRIBUTE_UNUSED)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_signed_vma foff = symval - (sec_addr (sec) + rel->r_offset);
@@ -3539,7 +3544,8 @@ _bfd_riscv_relax_lui (bfd *abfd,
                      bfd_vma max_alignment,
                      bfd_vma reserve_size,
                      bfd_boolean *again,
-                     riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED)
+                     riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
+                     bfd_boolean undefined_weak)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma gp = riscv_global_pointer_value (link_info);
@@ -3561,21 +3567,38 @@ _bfd_riscv_relax_lui (bfd *abfd,
 
   /* Is the reference in range of x0 or gp?
      Valid gp range conservatively because of alignment issue.  */
-  if (VALID_ITYPE_IMM (symval)
-      || (symval >= gp
-         && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
-      || (symval < gp
-         && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
+  if (undefined_weak
+      || (VALID_ITYPE_IMM (symval)
+         || (symval >= gp
+             && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
+         || (symval < gp
+             && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))))
     {
       unsigned sym = ELFNN_R_SYM (rel->r_info);
       switch (ELFNN_R_TYPE (rel->r_info))
        {
        case R_RISCV_LO12_I:
-         rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
+         if (undefined_weak)
+           {
+             /* Change the RS1 to zero.  */
+             bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset);
+             insn &= ~(OP_MASK_RS1 << OP_SH_RS1);
+             bfd_put_32 (abfd, insn, contents + rel->r_offset);
+           }
+         else
+           rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
          return TRUE;
 
        case R_RISCV_LO12_S:
-         rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
+         if (undefined_weak)
+           {
+             /* Change the RS1 to zero.  */
+             bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset);
+             insn &= ~(OP_MASK_RS1 << OP_SH_RS1);
+             bfd_put_32 (abfd, insn, contents + rel->r_offset);
+           }
+         else
+           rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
          return TRUE;
 
        case R_RISCV_HI20:
@@ -3634,7 +3657,8 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
                         bfd_vma max_alignment ATTRIBUTE_UNUSED,
                         bfd_vma reserve_size ATTRIBUTE_UNUSED,
                         bfd_boolean *again,
-                        riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED)
+                        riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED,
+                        bfd_boolean undefined_weak ATTRIBUTE_UNUSED)
 {
   /* See if this symbol is in range of tp.  */
   if (RISCV_CONST_HIGH_PART (tpoff (link_info, symval)) != 0)
@@ -3674,7 +3698,8 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
                        bfd_vma max_alignment ATTRIBUTE_UNUSED,
                        bfd_vma reserve_size ATTRIBUTE_UNUSED,
                        bfd_boolean *again ATTRIBUTE_UNUSED,
-                       riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED)
+                       riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED,
+                       bfd_boolean undefined_weak ATTRIBUTE_UNUSED)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma alignment = 1, pos;
@@ -3732,8 +3757,10 @@ _bfd_riscv_relax_pc  (bfd *abfd ATTRIBUTE_UNUSED,
                      bfd_vma max_alignment,
                      bfd_vma reserve_size,
                      bfd_boolean *again ATTRIBUTE_UNUSED,
-                     riscv_pcgp_relocs *pcgp_relocs)
+                     riscv_pcgp_relocs *pcgp_relocs,
+                     bfd_boolean undefined_weak)
 {
+  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   bfd_vma gp = riscv_global_pointer_value (link_info);
 
   BFD_ASSERT (rel->r_offset + 4 <= sec->size);
@@ -3763,12 +3790,19 @@ _bfd_riscv_relax_pc  (bfd *abfd ATTRIBUTE_UNUSED,
        hi_reloc = *hi;
        symval = hi_reloc.hi_addr;
        sym_sec = hi_reloc.sym_sec;
+
+       /* We can not know whether the undefined weak symbol is referenced
+          according to the information of R_RISCV_PCREL_LO12_I/S.  Therefore,
+          we have to record the 'undefined_weak' flag when handling the
+          corresponding R_RISCV_HI20 reloc in riscv_record_pcgp_hi_reloc.  */
+       undefined_weak = hi_reloc.undefined_weak;
       }
       break;
 
     case R_RISCV_PCREL_HI20:
       /* Mergeable symbols and code might later move out of range.  */
-      if (sym_sec->flags & (SEC_MERGE | SEC_CODE))
+      if (! undefined_weak
+         && sym_sec->flags & (SEC_MERGE | SEC_CODE))
        return TRUE;
 
       /* If the cooresponding lo relocation has already been seen then it's not
@@ -3796,23 +3830,50 @@ _bfd_riscv_relax_pc  (bfd *abfd ATTRIBUTE_UNUSED,
 
   /* Is the reference in range of x0 or gp?
      Valid gp range conservatively because of alignment issue.  */
-  if (VALID_ITYPE_IMM (symval)
-      || (symval >= gp
-         && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
-      || (symval < gp
-         && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
+  if (undefined_weak
+      || (VALID_ITYPE_IMM (symval)
+         || (symval >= gp
+             && VALID_ITYPE_IMM (symval - gp + max_alignment + reserve_size))
+         || (symval < gp
+             && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size))))
     {
       unsigned sym = hi_reloc.hi_sym;
       switch (ELFNN_R_TYPE (rel->r_info))
        {
        case R_RISCV_PCREL_LO12_I:
-         rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
-         rel->r_addend += hi_reloc.hi_addend;
+         if (undefined_weak)
+           {
+             /* Change the RS1 to zero, and then modify the relocation
+                type to R_RISCV_LO12_I.  */
+             bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset);
+             insn &= ~(OP_MASK_RS1 << OP_SH_RS1);
+             bfd_put_32 (abfd, insn, contents + rel->r_offset);
+             rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LO12_I);
+             rel->r_addend = hi_reloc.hi_addend;
+           }
+         else
+           {
+             rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
+             rel->r_addend += hi_reloc.hi_addend;
+           }
          return TRUE;
 
        case R_RISCV_PCREL_LO12_S:
-         rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
-         rel->r_addend += hi_reloc.hi_addend;
+         if (undefined_weak)
+           {
+             /* Change the RS1 to zero, and then modify the relocation
+                type to R_RISCV_LO12_S.  */
+             bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset);
+             insn &= ~(OP_MASK_RS1 << OP_SH_RS1);
+             bfd_put_32 (abfd, insn, contents + rel->r_offset);
+             rel->r_info = ELFNN_R_INFO (sym, R_RISCV_LO12_S);
+             rel->r_addend = hi_reloc.hi_addend;
+           }
+         else
+           {
+             rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
+             rel->r_addend += hi_reloc.hi_addend;
+           }
          return TRUE;
 
        case R_RISCV_PCREL_HI20:
@@ -3821,7 +3882,8 @@ _bfd_riscv_relax_pc  (bfd *abfd ATTRIBUTE_UNUSED,
                                      rel->r_addend,
                                      symval,
                                      ELFNN_R_SYM(rel->r_info),
-                                     sym_sec);
+                                     sym_sec,
+                                     undefined_weak);
          /* We can delete the unnecessary AUIPC and reloc.  */
          rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE);
          rel->r_addend = 4;
@@ -3847,7 +3909,8 @@ _bfd_riscv_relax_delete (bfd *abfd,
                         bfd_vma max_alignment ATTRIBUTE_UNUSED,
                         bfd_vma reserve_size ATTRIBUTE_UNUSED,
                         bfd_boolean *again ATTRIBUTE_UNUSED,
-                        riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED)
+                        riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
+                        bfd_boolean undefined_weak ATTRIBUTE_UNUSED)
 {
   if (!riscv_relax_delete_bytes(abfd, sec, rel->r_offset, rel->r_addend,
                                link_info))
@@ -3914,6 +3977,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
       int type = ELFNN_R_TYPE (rel->r_info);
       bfd_vma symval;
       char symtype;
+      bfd_boolean undefined_weak = FALSE;
 
       relax_func = NULL;
       if (info->relax_pass == 0)
@@ -4008,11 +4072,36 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+         if (h->root.type == bfd_link_hash_undefweak
+             && (relax_func == _bfd_riscv_relax_lui
+                 || relax_func == _bfd_riscv_relax_pc))
+           {
+             /* For the lui and auipc relaxations, since the symbol
+                value of an undefined weak symbol is always be zero,
+                we can optimize the patterns into a single LI/MV/ADDI
+                instruction.
+
+                Note that, creating shared libraries and pie output may
+                break the rule above.  Fortunately, since we do not relax
+                pc relocs when creating shared libraries and pie output,
+                and the absolute address access for R_RISCV_HI20 isn't
+                allowed when "-fPIC" is set, the problem of creating shared
+                libraries can not happen currently.  Once we support the
+                auipc relaxations when creating shared libraries, then we will
+                need the more rigorous checking for this optimization.  */
+             undefined_weak = TRUE;
+           }
+
          if (h->plt.offset != MINUS_ONE)
            {
              sym_sec = htab->elf.splt;
              symval = h->plt.offset;
            }
+         else if (undefined_weak)
+           {
+             symval = 0;
+             sym_sec = bfd_und_section_ptr;
+           }
          else if (h->root.u.def.section->output_section == NULL
                   || (h->root.type != bfd_link_hash_defined
                       && h->root.type != bfd_link_hash_defweak))
@@ -4065,7 +4154,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 
       if (!relax_func (abfd, sec, sym_sec, info, rel, symval,
                       max_alignment, reserve_size, again,
-                      &pcgp_relocs))
+                      &pcgp_relocs, undefined_weak))
        goto fail;
     }
 
index 3f62dad9cceaabb00c56965ea07410a221560bbd..57d4df713aa6da903674a6eb3fb91bea13b821f3 100644 (file)
@@ -1,3 +1,10 @@
+2019-09-20  Nelson Chu <nelson.chu@sifive.com>
+
+       * testsuite/ld-riscv-elf/weakref32.s: Add relaxable undef weak code.
+       * testsuite/ld-riscv-elf/weakref64.s: Likewise.
+       * testsuite/ld-riscv-elf/weakref32.d: Updated.
+       * testsuite/ld-riscv-elf/weakref64.d: Updated.
+
 2019-09-20  Alan Modra  <amodra@gmail.com>
 
        * emultempl/xtensaelf.em (xtensa_get_section_deps): Comment.
index 5ede7cb7f657db7ddabdb7755e7032a23178ba78..eaeb6dae7e358aa93eac557e45fc522351bfb128 100644 (file)
@@ -5,15 +5,16 @@
 Disassembly of section \.text:
 
 90000000 <_start>:
-90000000:      70000797                auipc   a5,0x70000
-90000004:      00078793                mv      a5,a5
-90000008:      02078263                beqz    a5,9000002c <_start\+0x2c>
-9000000c:      ff010113                addi    sp,sp,-16
-90000010:      00112623                sw      ra,12\(sp\)
-90000014:      00000097                auipc   ra,0x0
-90000018:      000000e7                jalr    zero # 0 <_start\-0x90000000>
-9000001c:      00c12083                lw      ra,12\(sp\)
-90000020:      01010113                addi    sp,sp,16
-90000024:      00000317                auipc   t1,0x0
-90000028:      00000067                jr      zero # 0 <_start\-0x90000000>
-9000002c:      00008067                ret
+90000000:      00000793                li      a5,0
+90000004:      02078663                beqz    a5,90000030 <_start\+0x30>
+90000008:      00000793                li      a5,0
+9000000c:      02078263                beqz    a5,90000030 <_start\+0x30>
+90000010:      ff010113                addi    sp,sp,-16
+90000014:      00112623                sw      ra,12\(sp\)
+90000018:      00000097                auipc   ra,0x0
+9000001c:      000000e7                jalr    zero # 0 <_start\-0x90000000>
+90000020:      00c12083                lw      ra,12\(sp\)
+90000024:      01010113                addi    sp,sp,16
+90000028:      00000317                auipc   t1,0x0
+9000002c:      00000067                jr      zero # 0 <_start\-0x90000000>
+90000030:      00008067                ret
index 14df041218849824d5a8a5fd50896f678b27812a..6c3d84de5f2ac69680313deb0917b30e138f707b 100644 (file)
@@ -4,6 +4,9 @@
        .globl  _start
        .type   _start, @function
 _start:
+       lui     a5,%hi(f)
+       addi    a5,a5,%lo(f)
+       beq     a5,zero,.L1
        lla     a5,f
        beqz    a5,.L1
        addi    sp,sp,-16
index 52db9c2d0c3bf72d9730f3d8c92f24073f73fc82..cc718a91a31f9a60b197ec4deda2b3c228c8c5e5 100644 (file)
@@ -5,15 +5,16 @@
 Disassembly of section \.text:
 
 0000000090000000 <_start>:
-    90000000:  000007b7                lui     a5,0x0
-    90000004:  00078793                mv      a5,a5
-    90000008:  02078263                beqz    a5,9000002c <_start\+0x2c>
-    9000000c:  ff010113                addi    sp,sp,-16
-    90000010:  00113423                sd      ra,8\(sp\)
-    90000014:  00000097                auipc   ra,0x0
-    90000018:  000000e7                jalr    zero # 0 <_start\-0x90000000>
-    9000001c:  00813083                ld      ra,8\(sp\)
-    90000020:  01010113                addi    sp,sp,16
-    90000024:  00000317                auipc   t1,0x0
-    90000028:  00000067                jr      zero # 0 <_start\-0x90000000>
-    9000002c:  00008067                ret
+    90000000:  00000793                li      a5,0
+    90000004:  02078663                beqz    a5,90000030 <_start\+0x30>
+    90000008:  00000793                li      a5,0
+    9000000c:  02078263                beqz    a5,90000030 <_start\+0x30>
+    90000010:  ff010113                addi    sp,sp,-16
+    90000014:  00113423                sd      ra,8\(sp\)
+    90000018:  00000097                auipc   ra,0x0
+    9000001c:  000000e7                jalr    zero # 0 <_start\-0x90000000>
+    90000020:  00813083                ld      ra,8\(sp\)
+    90000024:  01010113                addi    sp,sp,16
+    90000028:  00000317                auipc   t1,0x0
+    9000002c:  00000067                jr      zero # 0 <_start\-0x90000000>
+    90000030:  00008067                ret
index 5872626665aa080bb552af89b695e0ed4a019838..83bcd2856356b47b7f8845f9fc3938f0f2c34bd7 100644 (file)
@@ -4,6 +4,9 @@
        .globl  _start
        .type   _start, @function
 _start:
+       lui     a5,%hi(f)
+       addi    a5,a5,%lo(f)
+       beq     a5,zero,.L1
        lla     a5,f
        beqz    a5,.L1
        addi    sp,sp,-16