[lld] [LLD][RISCV] Add relaxation for absolute symbol whose hi20 can use c.lui (PR #86294)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 22 08:16:38 PDT 2024


https://github.com/preames created https://github.com/llvm/llvm-project/pull/86294

If we have an absolute address whose hi20 bits are known to be an int6, we can use a c.lui instead of a lui for the high bits.  This does not reduce dynamic icount, but does reduce codesize by 2 bytes.

>From 740848cfe05446a623ddfc59b45b9f9c18f02048 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Thu, 21 Mar 2024 16:13:53 -0700
Subject: [PATCH] [LLD][RISCV] Add relaxation for absolute symbol whose hi20
 can use c.lui

If we have an absolute address whose hi20 bits are known to be an int6,
we can use a c.lui instead of a lui for the high bits.  This does not
reduce dynamic icount, but does reduce codesize by 2 bytes.
---
 lld/ELF/Arch/RISCV.cpp                   | 51 +++++++++++++-------
 lld/test/ELF/riscv-relax-hi20-lo12-rvc.s | 60 ++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 17 deletions(-)
 create mode 100644 lld/test/ELF/riscv-relax-hi20-lo12-rvc.s

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 20de1b9b7bde96..9172349bc5ced2 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -70,7 +70,9 @@ enum Op {
 };
 
 enum Reg {
+  X_0 = 0,
   X_RA = 1,
+  X_2 = 2,
   X_GP = 3,
   X_TP = 4,
   X_T0 = 5,
@@ -789,25 +791,39 @@ 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) {
-  const Defined *gp = ElfSym::riscvGlobalPointer;
-  if (!gp)
-    return;
-
-  if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
+  if (const Defined *gp = ElfSym::riscvGlobalPointer;
+      gp && isInt<12>(r.sym->getVA(r.addend) - gp->getVA())) {
+    switch (r.type) {
+    case R_RISCV_RVC_LUI:
+      // Remove c.lui rd, %hi6(x).
+      sec.relaxAux->relocTypes[i] = R_RISCV_RELAX;
+      remove = 2;
+      break;
+    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_GPREL_I;
+      break;
+    case R_RISCV_LO12_S:
+      sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
+      break;
+    }
     return;
+  }
 
-  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_GPREL_I;
-    break;
-  case R_RISCV_LO12_S:
-    sec.relaxAux->relocTypes[i] = INTERNAL_R_RISCV_GPREL_S;
-    break;
+  // Use c.lui instead of lui if compressed and range allows
+  const bool rvc = getEFlags(sec.file) & EF_RISCV_RVC;
+  if (rvc && r.type == R_RISCV_HI20 && isInt<6>(hi20(r.sym->getVA(r.addend)))) {
+    if (uint32_t rd = (read32le(sec.content().data() + r.offset) >> 7) & 31;
+        rd != X_0 && rd != X_2) {
+      sec.relaxAux->relocTypes[i] = R_RISCV_RVC_LUI;
+      sec.relaxAux->writes.push_back(0x6001 | rd << 7); // c.lui
+      remove = 2;
+      return;
+    }
   }
 }
 
@@ -993,6 +1009,7 @@ void RISCV::finalizeRelax(int passes) const {
           case R_RISCV_RELAX:
             // Used by relaxTlsLe to indicate the relocation is ignored.
             break;
+          case R_RISCV_RVC_LUI:
           case R_RISCV_RVC_JUMP:
             skip = 2;
             write16le(p, aux.writes[writesIdx++]);
diff --git a/lld/test/ELF/riscv-relax-hi20-lo12-rvc.s b/lld/test/ELF/riscv-relax-hi20-lo12-rvc.s
new file mode 100644
index 00000000000000..9406e6be8fab68
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-hi20-lo12-rvc.s
@@ -0,0 +1,60 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf -mattr=+relax,+c a.s -o rv32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf -mattr=+relax,+c a.s -o rv64.o
+
+# RUN: ld.lld rv32.o lds -o rv32
+# RUN: ld.lld 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: 0000002c l       .text {{0*}}0 a
+
+# CHECK:      c.lui   a0, 0x1
+# CHECK-NEXT: addi    a0, a0, 0x0
+# CHECK-NEXT: lw      a0, 0x0(a0)
+# CHECK-NEXT: sw      a0, 0x0(a0)
+# CHECK-NEXT: c.lui   a0, 0x1f
+# CHECK-NEXT: addi    a0, a0, 0x7ff
+# CHECK-NEXT: lb      a0, 0x7ff(a0)
+# CHECK-NEXT: sb      a0, 0x7ff(a0)
+# CHECK-NEXT: lui     a0, 0x20
+# CHECK-NEXT: addi    a0, a0, -0x800
+# CHECK-NEXT: lw      a0, -0x800(a0)
+# CHECK-NEXT: sw      a0, -0x800(a0)
+# CHECK-EMPTY:
+# CHECK-NEXT: <a>:
+# CHECK-NEXT: c.addi a0, 0x1
+
+#--- a.s
+.global _start
+_start:
+  lui a0, %hi(rvc_lui_low)
+  addi a0, a0, %lo(rvc_lui_low)
+  lw a0, %lo(rvc_lui_low)(a0)
+  sw a0, %lo(rvc_lui_low)(a0)
+  lui a0, %hi(rvc_lui_high)
+  addi a0, a0, %lo(rvc_lui_high)
+  lb a0, %lo(rvc_lui_high)(a0)
+  sb a0, %lo(rvc_lui_high)(a0)
+  lui a0, %hi(norelax)
+  addi a0, a0, %lo(norelax)
+  lw a0, %lo(norelax)(a0)
+  sw a0, %lo(norelax)(a0)
+a:
+  addi a0, a0, 1
+
+.section .sdata,"aw"
+rvc_lui_low:
+  .space 124927
+rvc_lui_high:
+  .byte 0
+norelax:
+  .word 0
+
+#--- lds
+SECTIONS {
+  .text : {*(.text) }
+  .sdata 0x1000 : { }
+}



More information about the llvm-commits mailing list