[lld] [RISCV] Compress unrelaxable lui when RVC attribute is present (PR #74715)

Nemanja Ivanovic via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 7 05:29:31 PST 2023


https://github.com/nemanjai created https://github.com/llvm/llvm-project/pull/74715

If the object being linked allows compressed instructions, relaxation is on and we are unable to relax the HI20 relocation, emit c.lui instead of lui if the immediate fits.

>From 058c918d265c724d77ed8bb0482eefcd6604bbab Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Thu, 7 Dec 2023 14:15:40 +0100
Subject: [PATCH] [RISCV] Compress unrelaxable lui when RVC attribute is
 present

If the object being linked allows compressed instructions,
relaxation is on and we are unable to relax the HI20
relocation, emit c.lui instead of lui if the immediate
fits.
---
 lld/ELF/Arch/RISCV.cpp               | 30 ++++++++++++++++++
 lld/test/ELF/riscv-clui-relax-hi20.s | 46 ++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)
 create mode 100644 lld/test/ELF/riscv-clui-relax-hi20.s

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 898e3e45b9e72..eac835505bfcb 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -650,8 +650,37 @@ static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
   if (!gp)
     return;
 
+  bool noRelaxation = false;
   if (!isInt<12>(r.sym->getVA(r.addend) - gp->getVA()))
+    noRelaxation = true;
+
+  if (noRelaxation) {
+    if (r.type != R_RISCV_HI20 || !(config->eflags & EF_RISCV_RVC) ||
+        !isInt<18>(r.sym->getVA(r.addend)))
+      return;
+    // We have a HI20 reloc that fits in 18 bits but not in 12 bits
+    // and compressed instructions are enabled.
+    // Try to compress the lui to a c.lui.
+    const unsigned bits = config->wordsize * 8;
+    uint32_t rd =
+      extractBits(read32le(sec.content().data() + r.offset), 11, 7);
+    uint32_t newInsn = 0x6001 | (rd << 7); // c.lui
+    int64_t imm = SignExtend64(r.sym->getVA(r.addend) + 0x800, bits) >> 12;
+
+    // The high immediate may be outside the range if the low needs to be
+    // negative. So the isInt<18> check above is not sufficient. Also,
+    // rd != 2 for c.lui.
+    if (rd == 2 || !isInt<6>(imm))
+      return;
+    if (imm == 0)
+      newInsn &= 0xDFFF;
+    uint16_t imm17 = extractBits(imm, 17, 17) << 12;
+    uint16_t imm16_12 = extractBits(imm, 16, 12) << 2;
+    remove = 2;
+    sec.relaxAux->relocTypes[i] = R_RISCV_RVC_LUI;
+    sec.relaxAux->writes.push_back(newInsn | imm17 | imm16_12);
     return;
+  }
 
   switch (r.type) {
   case R_RISCV_HI20:
@@ -830,6 +859,7 @@ void elf::riscvFinalizeRelax(int passes) {
           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-clui-relax-hi20.s b/lld/test/ELF/riscv-clui-relax-hi20.s
new file mode 100644
index 0000000000000..ba3d4ecb9a54e
--- /dev/null
+++ b/lld/test/ELF/riscv-clui-relax-hi20.s
@@ -0,0 +1,46 @@
+# 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 --relax-gp --undefined=__global_pointer$ rv32.o lds -o rv32
+# RUN: ld.lld --relax-gp --undefined=__global_pointer$ rv64.o lds -o rv64
+# RUN: llvm-objdump -td -M no-aliases rv32 | FileCheck %s
+# RUN: llvm-objdump -td -M no-aliases rv64 | FileCheck %s
+
+# CHECK: 00002000 l       .data  {{0+}} foo
+# CHECK: 00002000 l       .data  {{0+}} $d.2
+# CHECK: 00001800 g       .sdata {{0+}} __global_pointer$
+
+# CHECK: <_start>:
+# CHECK: 09 65         c.lui   a0, 2
+# CHECK: 13 05 05 00   addi    a0, a0, 0
+# CHECK: 37 05 02 00   lui   a0, 32
+# CHECK: 13 05 05 00   addi    a0, a0, 0
+
+
+#--- a.s
+.global _start
+_start:
+  lui a0, %hi(foo)
+  addi a0, a0, %lo(foo)
+  lui a0, %hi(bar)
+  addi a0, a0, %lo(bar)
+
+.section .sdata,"aw"
+  .zero 32
+.section .data,"aw"
+foo:
+  .word 0
+.section .far,"aw"
+bar:
+  .word 0
+
+#--- lds
+SECTIONS {
+  .text : {*(.text) }
+  .sdata 0x1000 : { }
+  .data 0x2000 : { }
+  .far 0x20000 : { }
+}



More information about the llvm-commits mailing list