[lld] [RISCV] Disable gp relaxation if part of object unreachable (PR #72655)

via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 17 07:00:29 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: Nemanja Ivanovic (nemanjai)

<details>
<summary>Changes</summary>

Linker gp relaxation is greedy. It will eliminate the LUI with R_RISCV_HI20 if the base of the object is reachable from the gp. The relaxation on the R_RISCV_LO12 will be rejected if it is not reachable, but that is too late if the corresponding R_RISCV_HI20 is gone.
This patch disables relaxation if the entire portion of the object that can be relocated together is not reachable.

It is important that this does not necessarily mean the size of the object since the size doesn't matter if its alignment is smaller than its size.

In order to achieve correctness without excessively pessimizing relaxation for large objects, relaxation is rejected if the base of the object + min(s, ma) is not reachable from gp, where:
s  - size of the object
ma - maximum alignment of the section that contains
     the object.

---
Full diff: https://github.com/llvm/llvm-project/pull/72655.diff


2 Files Affected:

- (modified) lld/ELF/Arch/RISCV.cpp (+14) 
- (added) lld/test/ELF/riscv-relax-gp-partial.s (+58) 


``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 6413dcd7dcd7976..d4c578934a0bb39 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -651,6 +651,20 @@ static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
   if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
     return;
 
+  // The symbol may be accessed in multiple pieces. We need to make sure that
+  // all of the possible accesses are relaxed or none are. This prevents
+  // relaxing the hi relocation and being unable to relax one of the low
+  // relocations. The compiler will only access multiple pieces of an object
+  // with low relocations on the memory op if the alignment allows it.
+  // Therefore it should suffice to check that the smaller of the alignment
+  // and size can be reached from GP.
+  uint32_t alignAdjust =
+      r.sym->getOutputSection() ? r.sym->getOutputSection()->addralign : 0;
+  alignAdjust = std::min<uint32_t>(alignAdjust, r.sym->getSize());
+
+  if (!isInt<12>(r.sym->getVA() + alignAdjust - gp->getVA()))
+    return;
+
   switch (r.type) {
   case R_RISCV_HI20:
     // Remove lui rd, %hi20(x).
diff --git a/lld/test/ELF/riscv-relax-gp-partial.s b/lld/test/ELF/riscv-relax-gp-partial.s
new file mode 100644
index 000000000000000..79984d9b65b7cfb
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-gp-partial.s
@@ -0,0 +1,58 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax a.s -o rv64.o
+
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv32 | FileCheck %s
+# RUN: llvm-objdump -td -M no-aliases --no-show-raw-insn rv64 | FileCheck %s
+ 
+# CHECK: 00000080 l       .data  {{0+}}08 Var0
+# CHECK: 00001000 l       .data  {{0+}}80 Var1
+# CHECK: 00000815 g       .sdata {{0+}}00 __global_pointer$
+
+# CHECK: <_start>:
+# CHECK-NOT:  lui
+# CHECK-NEXT: lw      a0, -1941(gp)
+# CHECK-NEXT: lw      a1, -1937(gp)
+# CHECK-NEXT: lui     a1, 1
+# CHECK-NEXT: lw      a0, 0(a1)
+# CHECK-NEXT: lw      a1, 124(a1)
+
+#--- a.s
+.global _start
+_start:
+        lui     a1, %hi(Var0)
+        lw      a0, %lo(Var0)(a1)
+        lw      a1, %lo(Var0+4)(a1)
+        lui     a1, %hi(Var1)
+        lw      a0, %lo(Var1)(a1)      # First part is reachable from gp
+        lw      a1, %lo(Var1+124)(a1)  # The second part is not reachable
+
+.section .rodata
+foo:
+  .space 1
+.section .sdata,"aw"
+  .space 1
+.section .data,"aw"
+  .p2align 3
+Var0:
+  .quad 0
+  .size   Var0, 8
+  .space 3960
+  .p2align 7
+Var1:
+  .quad 0
+  .zero 120
+  .size   Var1, 128
+
+#--- lds
+    SECTIONS {
+        .text : { }
+        .rodata : { }
+        .sdata : { }
+        .sbss : { }
+        .data : { }
+    }

``````````

</details>


https://github.com/llvm/llvm-project/pull/72655


More information about the llvm-commits mailing list