0
0
mirror of https://github.com/llvm/llvm-project.git synced 2025-04-21 12:56:52 +00:00

[LLD][RISCV] Add relaxation for absolute int12 Hi20Lo12 ()

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.
This commit is contained in:
Philip Reames 2025-03-20 18:56:56 -07:00 committed by GitHub
parent 902078350e
commit 631769f2a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 4 deletions

@ -50,10 +50,12 @@ public:
} // 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.

@ -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 {