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

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 7 05:30:03 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-elf

Author: Nemanja Ivanovic (nemanjai)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/74715.diff


2 Files Affected:

- (modified) lld/ELF/Arch/RISCV.cpp (+29) 
- (added) lld/test/ELF/riscv-clui-relax-hi20.s (+46) 


``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 898e3e45b9e72..ffe1ece274f66 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -650,8 +650,36 @@ 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 +858,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..ef6284fd116b7
--- /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: 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 45 00   addi    a0, a0, 4
+# CHECK: 37 05 02 00   lui   a0, 32
+# CHECK: 13 05 45 00   addi    a0, a0, 4
+
+
+#--- 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 0x2004 : { }
+  .far 0x20004 : { }
+}

``````````

</details>


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


More information about the llvm-commits mailing list