[lld] [LLD][RISCV] Add relaxation for absolute int12 Hi20Lo12 (PR #86124)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 21 07:26:40 PDT 2024


https://github.com/preames created https://github.com/llvm/llvm-project/pull/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.

>From 9f64b25e74badeebf160dd649b5008136cd56d59 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Wed, 20 Mar 2024 13:29:42 -0700
Subject: [PATCH] [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.
---
 lld/ELF/Arch/RISCV.cpp               | 40 +++++++++++++++++++++++++++-
 lld/test/ELF/riscv-relax-hi20-lo12.s | 23 +++++++++++++---
 2 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 20de1b9b7bde96..d59a2e2d3d2c03 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,
@@ -464,6 +467,20 @@ 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: {
+    assert(isInt<12>(val));
+    uint64_t hi = (val + 0x800) >> 12;
+    uint64_t lo = val - (hi << 12);
+    uint32_t insn = (read32le(loc) & ~(31 << 15)) | (X_X0 << 15);
+    if (rel.type == INTERNAL_R_RISCV_X0REL_I)
+      insn = setLO12_I(insn, lo);
+    else
+      insn = setLO12_S(insn, lo);
+    write32le(loc, insn);
+    return;
+  }
+
   case INTERNAL_R_RISCV_GPREL_I:
   case INTERNAL_R_RISCV_GPREL_S: {
     Defined *gp = ElfSym::riscvGlobalPointer;
@@ -789,6 +806,25 @@ static void relaxTlsLe(const InputSection &sec, size_t i, uint64_t loc,
 
 static void relaxHi20Lo12(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(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 = ElfSym::riscvGlobalPointer;
   if (!gp)
     return;
@@ -989,6 +1025,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 6bb29b12348f80..aa10e957cc60ed 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