[lld] [RISCV] Disable gp relaxation if part of object unreachable (PR #72655)
Nemanja Ivanovic via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 17 07:00:02 PST 2023
https://github.com/nemanjai created https://github.com/llvm/llvm-project/pull/72655
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.
>From 61f44ad222d9379fab4722ce57aa94ce20b042e7 Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Fri, 17 Nov 2023 15:49:11 +0100
Subject: [PATCH] [RISCV] Disable gp relaxation if part of object unreachable
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.
---
lld/ELF/Arch/RISCV.cpp | 14 +++++++
lld/test/ELF/riscv-relax-gp-partial.s | 58 +++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 lld/test/ELF/riscv-relax-gp-partial.s
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 : { }
+ }
More information about the llvm-commits
mailing list