[lld] 631769f - [LLD][RISCV] Add relaxation for absolute int12 Hi20Lo12 (#86124)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 20 18:57:00 PDT 2025
Author: Philip Reames
Date: 2025-03-20T18:56:56-07:00
New Revision: 631769f2a05a082eafa03b7f99502381da704d7d
URL: https://github.com/llvm/llvm-project/commit/631769f2a05a082eafa03b7f99502381da704d7d
DIFF: https://github.com/llvm/llvm-project/commit/631769f2a05a082eafa03b7f99502381da704d7d.diff
LOG: [LLD][RISCV] Add relaxation for absolute int12 Hi20Lo12 (#86124)
If we have an absolute address whose high bits are known to be a sign
extend of the low 12 bits, we can avoid emitting the LUI entirely. This
is implemented in an analogous manner to the gp relative relocations -
defining an internal usage relocation type.
Since 12 bits (really 11 since the high bit must be zero in user code)
is less than one page, all of these offsets fit in the null page. As
such, the only application of these is likely to be undefined weak
symbols except for embedded use cases. I'm mostly posting this for
completeness sake.
Added:
Modified:
lld/ELF/Arch/RISCV.cpp
lld/test/ELF/riscv-relax-hi20-lo12.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 4d8989a21b501..abe8876668a45 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -50,10 +50,12 @@ class RISCV final : public TargetInfo {
} // end anonymous namespace
-// These are internal relocation numbers for GP relaxation. They aren't part
+// These are internal relocation numbers for GP/X0 relaxation. They aren't part
// of the psABI spec.
#define INTERNAL_R_RISCV_GPREL_I 256
#define INTERNAL_R_RISCV_GPREL_S 257
+#define INTERNAL_R_RISCV_X0REL_I 258
+#define INTERNAL_R_RISCV_X0REL_S 259
const uint64_t dtpOffset = 0x800;
@@ -70,6 +72,7 @@ enum Op {
};
enum Reg {
+ X_X0 = 0,
X_RA = 1,
X_GP = 3,
X_TP = 4,
@@ -447,6 +450,18 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
return;
}
+ case INTERNAL_R_RISCV_X0REL_I:
+ case INTERNAL_R_RISCV_X0REL_S: {
+ checkInt(ctx, loc, val, 12, rel);
+ uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_X0 << 15);
+ if (rel.type == INTERNAL_R_RISCV_X0REL_I)
+ insn = setLO12_I(insn, val);
+ else
+ insn = setLO12_S(insn, val);
+ write32le(loc, insn);
+ return;
+ }
+
case INTERNAL_R_RISCV_GPREL_I:
case INTERNAL_R_RISCV_GPREL_S: {
Defined *gp = ctx.sym.riscvGlobalPointer;
@@ -772,6 +787,25 @@ static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i,
static void relaxHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
uint64_t loc, Relocation &r, uint32_t &remove) {
+
+ // Fold into use of x0+offset
+ if (isInt<12>(r.sym->getVA(ctx, r.addend))) {
+ switch (r.type) {
+ case R_RISCV_HI20:
+ // Remove lui rd, %hi20(x).
+ sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
+ remove = 4;
+ break;
+ case R_RISCV_LO12_I:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_X0REL_I;
+ break;
+ case R_RISCV_LO12_S:
+ sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_X0REL_S;
+ break;
+ }
+ return;
+ }
+
const Defined *gp = ctx.sym.riscvGlobalPointer;
if (!gp)
return;
@@ -974,6 +1008,8 @@ void RISCV::finalizeRelax(int passes) const {
switch (newType) {
case INTERNAL_R_RISCV_GPREL_I:
case INTERNAL_R_RISCV_GPREL_S:
+ case INTERNAL_R_RISCV_X0REL_I:
+ case INTERNAL_R_RISCV_X0REL_S:
break;
case R_RISCV_RELAX:
// Used by relaxTlsLe to indicate the relocation is ignored.
diff --git a/lld/test/ELF/riscv-relax-hi20-lo12.s b/lld/test/ELF/riscv-relax-hi20-lo12.s
index 6bb29b12348f8..aa10e957cc60e 100644
--- a/lld/test/ELF/riscv-relax-hi20-lo12.s
+++ b/lld/test/ELF/riscv-relax-hi20-lo12.s
@@ -4,12 +4,12 @@
# 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: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ --defsym baz=420 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: 00000028 l .text {{0*}}0 a
+# CHECK: 00000040 l .text {{0*}}0 a
# CHECK-NOT: lui
# CHECK: addi a0, gp, -0x800
@@ -23,6 +23,14 @@
# CHECK-NEXT: addi a0, a0, 0x0
# CHECK-NEXT: lw a0, 0x0(a0)
# CHECK-NEXT: sw a0, 0x0(a0)
+# CHECK-NOT: lui
+# CHECK: addi a0, zero, 0x0
+# CHECK-NEXT: lw a0, 0x0(zero)
+# CHECK-NEXT: sw a0, 0x0(zero)
+# CHECK-NOT: lui
+# CHECK: addi a0, zero, 0x1a4
+# CHECK-NEXT: lw a0, 0x1a4(zero)
+# CHECK-NEXT: sw a0, 0x1a4(zero)
# CHECK-EMPTY:
# CHECK-NEXT: <a>:
# CHECK-NEXT: addi a0, a0, 0x1
@@ -42,6 +50,14 @@ _start:
addi a0, a0, %lo(norelax)
lw a0, %lo(norelax)(a0)
sw a0, %lo(norelax)(a0)
+ lui a0, %hi(undefined_weak)
+ addi a0, a0, %lo(undefined_weak)
+ lw a0, %lo(undefined_weak)(a0)
+ sw a0, %lo(undefined_weak)(a0)
+ lui a0, %hi(baz)
+ addi a0, a0, %lo(baz)
+ lw a0, %lo(baz)(a0)
+ sw a0, %lo(baz)(a0)
a:
addi a0, a0, 1
@@ -53,6 +69,7 @@ bar:
.byte 0
norelax:
.word 0
+.weak undefined_weak
#--- lds
SECTIONS {
More information about the llvm-commits
mailing list