[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:43 PST 2023


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

>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 1/2] [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 : { }
+}

>From 664961880ae99b62c97752ae4a53c1bffc7ed024 Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja at synopsys.com>
Date: Thu, 7 Dec 2023 14:29:01 +0100
Subject: [PATCH 2/2] Run clang-format

---
 lld/ELF/Arch/RISCV.cpp               |  3 +--
 lld/test/ELF/riscv-clui-relax-hi20.s | 12 ++++++------
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index eac835505bfcb..ffe1ece274f66 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -662,8 +662,7 @@ static void relaxHi20Lo12(const InputSection &sec, size_t i, uint64_t loc,
     // 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 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;
 
diff --git a/lld/test/ELF/riscv-clui-relax-hi20.s b/lld/test/ELF/riscv-clui-relax-hi20.s
index ba3d4ecb9a54e..ef6284fd116b7 100644
--- a/lld/test/ELF/riscv-clui-relax-hi20.s
+++ b/lld/test/ELF/riscv-clui-relax-hi20.s
@@ -9,15 +9,15 @@
 # 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: 00002004 l       .data  {{0+}} foo
+# CHECK: 00020004 l       .far   {{0+}} bar
 # 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: 13 05 45 00   addi    a0, a0, 4
 # CHECK: 37 05 02 00   lui   a0, 32
-# CHECK: 13 05 05 00   addi    a0, a0, 0
+# CHECK: 13 05 45 00   addi    a0, a0, 4
 
 
 #--- a.s
@@ -41,6 +41,6 @@ bar:
 SECTIONS {
   .text : {*(.text) }
   .sdata 0x1000 : { }
-  .data 0x2000 : { }
-  .far 0x20000 : { }
+  .data 0x2004 : { }
+  .far 0x20004 : { }
 }



More information about the llvm-commits mailing list