[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