[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