[lld] [lld][LoongArch] Relax PCHi20Lo12: R_LARCH_{PCALA,GOT_PC}_{HI20,LO12} (PR #122209)
Zhaoxin Yang via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 15 01:39:55 PST 2025
https://github.com/ylzsx updated https://github.com/llvm/llvm-project/pull/122209
>From 5d7dee4e570fee77d5a442af523d0d9e81b0a4b8 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 15:32:34 +0800
Subject: [PATCH 1/6] Relax PCHi20Lo12.
Support relaxation optimization for two types of code sequences.
```
From:
pcalau12i $a0, %pc_hi20(sym)
R_LARCH_PCALA_HI20, R_LARCH_RELAX
addi.w/d $a0, $a0, %pc_lo12(sym)
R_LARCH_PCALA_LO12, R_LARCH_RELAX
To:
pcaddi $a0, %pc_lo12(sym)
R_LARCH_PCREL20_S2
From:
pcalau12i $a0, %got_pc_hi20(sym_got)
R_LARCH_GOT_PC_HI20, R_LARCH_RELAX
ld.w/d $a0, $a0, %got_pc_lo12(sym_got)
R_LARCH_GOT_PC_LO12, R_LARCH_RELAX
To:
pcaddi $a0, %got_pc_hi20(sym_got)
R_LARCH_PCREL20_S2
```
---
lld/ELF/Arch/LoongArch.cpp | 104 ++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 2 deletions(-)
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index 3280c34cb6ed05..f5adb6555e6021 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -53,6 +53,7 @@ enum Op {
ADDI_W = 0x02800000,
ADDI_D = 0x02c00000,
ANDI = 0x03400000,
+ PCADDI = 0x18000000,
PCADDU12I = 0x1c000000,
LD_W = 0x28800000,
LD_D = 0x28c00000,
@@ -131,6 +132,8 @@ static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) {
return begin == 63 ? v >> end : (v & ((1ULL << (begin + 1)) - 1)) >> end;
}
+static uint32_t getD5(uint64_t v) { return extractBits(v, 4, 0); }
+
static uint32_t setD5k16(uint32_t insn, uint32_t imm) {
uint32_t immLo = extractBits(imm, 15, 0);
uint32_t immHi = extractBits(imm, 20, 16);
@@ -743,6 +746,78 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
}
}
+static bool relaxable(ArrayRef<Relocation> relocs, size_t i) {
+ return i + 1 < relocs.size() && relocs[i + 1].type == R_LARCH_RELAX;
+}
+
+static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
+ return relaxable(relocs, i) && relaxable(relocs, i + 2) &&
+ relocs[i].offset + 4 == relocs[i + 2].offset;
+}
+
+// Relax code sequence.
+// From:
+// pcalau12i $a0, %pc_hi20(sym)
+// addi.w/d $a0, $a0, %pc_lo12(sym)
+// To:
+// pcaddi $a0, %pc_lo12(sym)
+//
+// From:
+// pcalau12i $a0, %got_pc_hi20(sym_got)
+// ld.w/d $a0, $a0, %got_pc_lo12(sym_got)
+// To:
+// pcaddi $a0, %got_pc_hi20(sym_got)
+static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
+ uint64_t loc, Relocation &rHi20, Relocation &rLo12,
+ uint32_t &remove) {
+ // check if the relocations are relaxable sequences.
+ if (!((rHi20.type == R_LARCH_PCALA_HI20 &&
+ rLo12.type == R_LARCH_PCALA_LO12) ||
+ (rHi20.type == R_LARCH_GOT_PC_HI20 &&
+ rLo12.type == R_LARCH_GOT_PC_LO12)))
+ return;
+
+ // GOT references to absolute symbols can't be relaxed to use pcaddi in
+ // position-independent code, because these instructions produce a relative
+ // address.
+ // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because
+ // these symbols may be resolve in runtime.
+ if (rHi20.type == R_LARCH_GOT_PC_HI20 &&
+ (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible ||
+ rHi20.sym->isGnuIFunc() ||
+ (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section)))
+ return;
+
+ uint64_t symBase = 0;
+ if (rHi20.expr == RE_LOONGARCH_PLT_PAGE_PC)
+ symBase = rHi20.sym->getPltVA(ctx);
+ else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
+ rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
+ symBase = rHi20.sym->getVA(ctx);
+ else {
+ Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr ("
+ << rHi20.expr << ") against symbol " << rHi20.sym
+ << "in relaxPCHi20Lo12";
+ return;
+ }
+ const uint64_t symLocal = symBase + rHi20.addend;
+
+ const int64_t distance = symLocal - loc;
+ // Check if the distance aligns 4 bytes or exceeds the range of pcaddi.
+ if ((distance & 0x3) != 0 || !isInt<22>(distance))
+ return;
+
+ // Note: If we can ensure that the .o files generated by LLVM only contain
+ // relaxable instruction sequences with R_LARCH_RELAX, then we do not need to
+ // check instruction opcodes.
+ const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset);
+
+ sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
+ sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
+ sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0));
+ remove = 4;
+}
+
static bool relax(Ctx &ctx, InputSection &sec) {
const uint64_t secAddr = sec.getVA();
const MutableArrayRef<Relocation> relocs = sec.relocs();
@@ -781,6 +856,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
}
break;
}
+ case R_LARCH_PCALA_HI20:
+ case R_LARCH_GOT_PC_HI20:
+ // The overflow check for i+2 will be carried out in isPairRelaxable.
+ if (isPairRelaxable(relocs, i))
+ relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove);
+ break;
}
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -851,6 +932,7 @@ void LoongArch::finalizeRelax(int passes) const {
MutableArrayRef<Relocation> rels = sec->relocs();
ArrayRef<uint8_t> old = sec->content();
size_t newSize = old.size() - aux.relocDeltas[rels.size() - 1];
+ size_t writesIdx = 0;
uint8_t *p = ctx.bAlloc.Allocate<uint8_t>(newSize);
uint64_t offset = 0;
int64_t delta = 0;
@@ -867,11 +949,29 @@ void LoongArch::finalizeRelax(int passes) const {
continue;
// Copy from last location to the current relocated location.
- const Relocation &r = rels[i];
+ Relocation &r = rels[i];
uint64_t size = r.offset - offset;
memcpy(p, old.data() + offset, size);
p += size;
- offset = r.offset + remove;
+
+ int64_t skip = 0;
+ if (RelType newType = aux.relocTypes[i]) {
+ switch (newType) {
+ case R_LARCH_RELAX:
+ break;
+ case R_LARCH_PCREL20_S2:
+ skip = 4;
+ write32le(p, aux.writes[writesIdx++]);
+ // RelExpr is needed for relocating.
+ r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
+ break;
+ default:
+ llvm_unreachable("unsupported type");
+ }
+ }
+
+ p += skip;
+ offset = r.offset + skip + remove;
}
memcpy(p, old.data() + offset, old.size() - offset);
>From 5da186380b363a1abdb8cc9e7ea6f654c5b11061 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Tue, 24 Dec 2024 08:57:29 +0800
Subject: [PATCH 2/6] la.pcrel relax test modify.
---
lld/test/ELF/loongarch-relax-align.s | 115 ++++++++++++++-------
lld/test/ELF/loongarch-relax-emit-relocs.s | 41 +++++---
2 files changed, 101 insertions(+), 55 deletions(-)
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index ab61e15d5caca2..9eaff9144d85e8 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -6,56 +6,91 @@
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64n | FileCheck --check-prefixes=NORELAX,NOOLD %s
## Test the R_LARCH_ALIGN without symbol index.
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64
# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck %s
-# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s
## -r keeps section contents unchanged.
# RUN: ld.lld -r %t.64.o -o %t.64.r
# RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
-# CHECK-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start
-# CHECK-DAG: {{0*}}10038 l .text {{0*}}0c .L1
-# CHECK-DAG: {{0*}}10040 l .text {{0*}}04 .L2
-# CHECK-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
-
-# CHECK: <.Ltext_start>:
-# CHECK-NEXT: break 1
-# CHECK-NEXT: break 2
-# CHECK-NEXT: nop
-# CHECK-NEXT: nop
-# CHECK-NEXT: break 3
-# CHECK-NEXT: break 4
-# CHECK-NEXT: nop
-# CHECK-NEXT: nop
-# CHECK-NEXT: pcalau12i $a0, 0
-# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT: pcalau12i $a0, 0
-# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 56
-# CHECK-NEXT: pcalau12i $a0, 0
-# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 64
-# CHECK-EMPTY:
-# CHECK-NEXT: <.L1>:
-# CHECK-NEXT: nop
-# CHECK-NEXT: nop
-# CHECK-EMPTY:
-# CHECK-NEXT: <.L2>:
-# CHECK-NEXT: break 5
-
-# CHECK: <.Ltext2_start>:
-# CHECK-NEXT: pcalau12i $a0, 0
-# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT: nop
-# CHECK-NEXT: nop
-# CHECK-NEXT: break 6
+# NOOLD: {{0*}}10000 l .text {{0*}}00 .Lalign_symbol
+# OLD: {{0*}}00001 l *ABS* {{0*}}00 old
+
+# NORELAX-DAG: {{0*}}10000 l .text {{0*}}44 .Ltext_start
+# NORELAX-DAG: {{0*}}10038 l .text {{0*}}0c .L1
+# NORELAX-DAG: {{0*}}10040 l .text {{0*}}04 .L2
+# NORELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# NORELAX: <.Ltext_start>:
+# NORELAX-NEXT: break 1
+# NORELAX-NEXT: break 2
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: break 3
+# NORELAX-NEXT: break 4
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: pcalau12i $a0, 0
+# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 0
+# NORELAX-NEXT: pcalau12i $a0, 0
+# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 56
+# NORELAX-NEXT: pcalau12i $a0, 0
+# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 64
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <.L1>:
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: nop
+# NORELAX-EMPTY:
+# NORELAX-NEXT: <.L2>:
+# NORELAX-NEXT: break 5
+
+# NORELAX: <.Ltext2_start>:
+# NORELAX-NEXT: pcalau12i $a0, 0
+# NORELAX-NEXT: addi.{{[dw]}} $a0, $a0, 0
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: break 6
+
+
+# RELAX-DAG: {{0*}}10000 l .text {{0*}}34 .Ltext_start
+# RELAX-DAG: {{0*}}1002c l .text {{0*}}08 .L1
+# RELAX-DAG: {{0*}}10030 l .text {{0*}}04 .L2
+# RELAX-DAG: {{0*}}20000 l .text2 {{0*}}14 .Ltext2_start
+
+# RELAX: <.Ltext_start>:
+# RELAX-NEXT: break 1
+# RELAX-NEXT: break 2
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+# RELAX-NEXT: break 3
+# RELAX-NEXT: break 4
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+# RELAX-NEXT: pcaddi $a0, -8
+# RELAX-NEXT: pcaddi $a0, 2
+# RELAX-NEXT: pcaddi $a0, 2
+# RELAX-EMPTY:
+# RELAX-NEXT: <.L1>:
+# RELAX-NEXT: nop
+# RELAX-EMPTY:
+# RELAX-NEXT: <.L2>:
+# RELAX-NEXT: break 5
+
+# RELAX: <.Ltext2_start>:
+# RELAX-NEXT: pcaddi $a0, 0
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+# RELAX-NEXT: break 6
# CHECKR: <.Ltext2_start>:
# CHECKR-NEXT: pcalau12i $a0, 0
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index ba414e8c93f0fb..7bc1f2d29c319c 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -5,29 +5,40 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32
# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
-# RUN: llvm-objdump -dr %t.32 | FileCheck %s
-# RUN: llvm-objdump -dr %t.64 | FileCheck %s
+# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
+# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
## -r should keep original relocations.
# RUN: ld.lld -r %t.64.o -o %t.64.r
# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
## --no-relax should keep original relocations.
-## TODO Due to R_LARCH_RELAX is not relaxed, it plays same as --relax now.
# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
-# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s
+# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
-# CHECK: 00010000 <_start>:
-# CHECK-NEXT: pcalau12i $a0, 0
-# CHECK-NEXT: R_LARCH_PCALA_HI20 _start
-# CHECK-NEXT: R_LARCH_RELAX *ABS*
-# CHECK-NEXT: addi.{{[dw]}} $a0, $a0, 0
-# CHECK-NEXT: R_LARCH_PCALA_LO12 _start
-# CHECK-NEXT: R_LARCH_RELAX *ABS*
-# CHECK-NEXT: nop
-# CHECK-NEXT: R_LARCH_ALIGN *ABS*+0xc
-# CHECK-NEXT: nop
-# CHECK-NEXT: ret
+# RELAX: 00010000 <_start>:
+# RELAX-NEXT: pcaddi $a0, 0
+# RELAX-NEXT: R_LARCH_RELAX _start
+# RELAX-NEXT: R_LARCH_RELAX *ABS*
+# RELAX-NEXT: R_LARCH_PCREL20_S2 _start
+# RELAX-NEXT: R_LARCH_RELAX *ABS*
+# RELAX-NEXT: nop
+# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
+# RELAX-NEXT: nop
+# RELAX-NEXT: nop
+# RELAX-NEXT: ret
+
+# NORELAX: <_start>:
+# NORELAX-NEXT: pcalau12i $a0, 0
+# NORELAX-NEXT: R_LARCH_PCALA_HI20 _start
+# NORELAX-NEXT: R_LARCH_RELAX *ABS*
+# NORELAX-NEXT: addi.d $a0, $a0, 0
+# NORELAX-NEXT: R_LARCH_PCALA_LO12 _start
+# NORELAX-NEXT: R_LARCH_RELAX *ABS*
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
+# NORELAX-NEXT: nop
+# NORELAX-NEXT: ret
# CHECKR: <_start>:
# CHECKR-NEXT: pcalau12i $a0, 0
>From 0d37ae987b682292ae2b5936176568f01a81aadd Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Fri, 27 Dec 2024 17:33:47 +0800
Subject: [PATCH 3/6] Add test for PCHi20Lo12
---
lld/test/ELF/loongarch-relax-emit-relocs.s | 33 ++++++++---
lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 62 +++++++++++++++++++++
2 files changed, 86 insertions(+), 9 deletions(-)
create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 7bc1f2d29c319c..9f3206b7ce54ce 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -3,8 +3,8 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.32.o -o %t.32
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs %t.64.o -o %t.64
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
@@ -13,7 +13,7 @@
# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
## --no-relax should keep original relocations.
-# RUN: ld.lld -Ttext=0x10000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --no-relax %t.64.o -o %t.64.norelax
# RUN: llvm-objdump -dr %t.64.norelax | FileCheck %s --check-prefix=NORELAX
# RELAX: 00010000 <_start>:
@@ -22,31 +22,45 @@
# RELAX-NEXT: R_LARCH_RELAX *ABS*
# RELAX-NEXT: R_LARCH_PCREL20_S2 _start
# RELAX-NEXT: R_LARCH_RELAX *ABS*
+# RELAX-NEXT: pcaddi $a0, -1
+# RELAX-NEXT: R_LARCH_RELAX _start
+# RELAX-NEXT: R_LARCH_RELAX *ABS*
+# RELAX-NEXT: R_LARCH_PCREL20_S2 _start
+# RELAX-NEXT: R_LARCH_RELAX *ABS*
# RELAX-NEXT: nop
# RELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
# RELAX-NEXT: nop
-# RELAX-NEXT: nop
# RELAX-NEXT: ret
# NORELAX: <_start>:
# NORELAX-NEXT: pcalau12i $a0, 0
# NORELAX-NEXT: R_LARCH_PCALA_HI20 _start
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
-# NORELAX-NEXT: addi.d $a0, $a0, 0
+# NORELAX-NEXT: addi.d $a0, $a0, 0
# NORELAX-NEXT: R_LARCH_PCALA_LO12 _start
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
-# NORELAX-NEXT: nop
-# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
-# NORELAX-NEXT: nop
+# NORELAX-NEXT: pcalau12i $a0, 16
+# NORELAX-NEXT: R_LARCH_GOT_PC_HI20 _start
+# NORELAX-NEXT: R_LARCH_RELAX *ABS*
+# NORELAX-NEXT: ld.d $a0, $a0, 0
+# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 _start
+# NORELAX-NEXT: R_LARCH_RELAX *ABS*
# NORELAX-NEXT: ret
+# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
# CHECKR: <_start>:
# CHECKR-NEXT: pcalau12i $a0, 0
# CHECKR-NEXT: R_LARCH_PCALA_HI20 _start
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
-# CHECKR-NEXT: addi.d $a0, $a0, 0
+# CHECKR-NEXT: addi.d $a0, $a0, 0
# CHECKR-NEXT: R_LARCH_PCALA_LO12 _start
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
+# CHECKR-NEXT: pcalau12i $a0, 0
+# CHECKR-NEXT: R_LARCH_GOT_PC_HI20 _start
+# CHECKR-NEXT: R_LARCH_RELAX *ABS*
+# CHECKR-NEXT: ld.d $a0, $a0, 0
+# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 _start
+# CHECKR-NEXT: R_LARCH_RELAX *ABS*
# CHECKR-NEXT: nop
# CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc
# CHECKR-NEXT: nop
@@ -56,5 +70,6 @@
.global _start
_start:
la.pcrel $a0, _start
+ la.got $a0, _start
.p2align 4
ret
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
new file mode 100644
index 00000000000000..a417d89e9fa2e4
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -0,0 +1,62 @@
+# REQUIRES: loongarch
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
+
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
+# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
+# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
+
+# RELAX-LABEL: <_start>:
+## offset = 0x14000 - 0x10000 = 4096<<2
+# RELAX-NEXT: 10000: pcaddi $a0, 4096
+# RELAX-NEXT: pcaddi $a0, 4095
+# RELAX-NEXT: pcaddi $a0, 4094
+# RELAX-NEXT: pcaddi $a0, 4093
+
+# NORELAX32-LABEL: <_start>:
+## offset exceed range of pcaddi
+## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
+# NORELAX32-NEXT: 10000: pcalau12i $a0, 1024
+# NORELAX32-NEXT: addi.w $a0, $a0, 0
+# NORELAX32-NEXT: pcalau12i $a0, 1024
+# NORELAX32-NEXT: ld.w $a0, $a0, 4
+# NORELAX32-NEXT: pcalau12i $a0, 1024
+# NORELAX32-NEXT: addi.w $a0, $a0, 0
+# NORELAX32-NEXT: pcalau12i $a0, 1024
+# NORELAX32-NEXT: ld.w $a0, $a0, 4
+
+# NORELAX64-LABEL: <_start>:
+## offset exceed range of pcaddi
+## offset = 0x410000 - 0x10000: 0x400 pages, page offset 0
+# NORELAX64-NEXT: 10000: pcalau12i $a0, 1024
+# NORELAX64-NEXT: addi.d $a0, $a0, 0
+# NORELAX64-NEXT: pcalau12i $a0, 1024
+# NORELAX64-NEXT: ld.d $a0, $a0, 8
+# NORELAX64-NEXT: pcalau12i $a0, 1024
+# NORELAX64-NEXT: addi.d $a0, $a0, 0
+# NORELAX64-NEXT: pcalau12i $a0, 1024
+# NORELAX64-NEXT: ld.d $a0, $a0, 8
+
+.section .text
+.global _start
+_start:
+ la.local $a0, sym
+ la.global $a0, sym
+ la.pcrel $a0, sym
+ la.got $a0, sym
+
+.section .data
+sym:
+ .zero 4
>From c73c04789772aedc7723c1dc344064976188a8d3 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Mon, 30 Dec 2024 19:29:43 +0800
Subject: [PATCH 4/6] Add test for got symbols relaxation.
Similar to aarch64-adrp-ldr-got-symbols.s.
---
...loongarch-relax-pc-hi20-lo12-got-symbols.s | 90 +++++++++++++++++++
1 file changed, 90 insertions(+)
create mode 100644 lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
new file mode 100644
index 00000000000000..bafb631bccb91b
--- /dev/null
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
@@ -0,0 +1,90 @@
+## This test verifies that the pair pcalau12i + ld.w/d is relaxed/not relaxed
+## depending on the target symbol properties.
+
+# REQUIRES: loongarch
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax symbols.s -o symbols.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax symbols.s -o symbols.64.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
+
+# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
+# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s
+
+# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
+# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s
+# RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s
+
+
+## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
+LIB: pcaddi $a0, {{[0-9]+}}
+## Symbol 'global_sym' is preemptible, no relaxations should be applied.
+LIB-NEXT: pcalau12i $a1, 4
+LIB-NEXT: ld.{{[wd]}} $a1, $a1, {{[0-9]+}}
+## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
+LIB-NEXT: pcalau12i $a2, 4
+LIB-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
+LIB-NEXT: pcalau12i $a3, 4
+LIB-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+## Symbol 'abs_sym' is absolute, no relaxations should be applied.
+LIB-NEXT: pcalau12i $a4, 4
+LIB-NEXT: ld.{{[wd]}} $a4, $a4, {{[0-9]+}}
+
+
+## Symbol 'hidden_sym' is nonpreemptible, the relaxation should be applied.
+EXE: pcaddi $a0, {{[0-9]+}}
+## Symbol 'global_sym' is nonpreemptible, the relaxation should be applied.
+EXE-NEXT: pcaddi $a1, {{[0-9]+}}
+## Symbol 'undefined_sym' is undefined, no relaxations should be applied.
+EXE-NEXT: pcalau12i $a2, 4
+EXE-NEXT: ld.{{[wd]}} $a2, $a2, {{[0-9]+}}
+## Symbol 'ifunc_sym' is STT_GNU_IFUNC, no relaxations should be applied.
+EXE-NEXT: pcalau12i $a3, 4
+EXE-NEXT: ld.{{[wd]}} $a3, $a3, {{[0-9]+}}
+## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode.
+EXE-NEXT: pcaddi $a4, -{{[0-9]+}}
+
+
+## The linker script ensures that .rodata and .text are near (>4M) so that
+## the pcalau12i+ld.w/d pair can be relaxed to pcaddi.
+#--- linker.t
+SECTIONS {
+ .text 0x10000: { *(.text) }
+ .rodata 0x14000: { *(.rodata) }
+}
+
+# This symbol is defined in a separate file to prevent the definition from
+# being folded into the instructions that reference it.
+#--- abs.s
+.global abs_sym
+.hidden abs_sym
+abs_sym = 0x1000
+
+#--- symbols.s
+.rodata
+.hidden hidden_sym
+hidden_sym:
+.word 10
+
+.global global_sym
+global_sym:
+.word 10
+
+.text
+.type ifunc_sym STT_GNU_IFUNC
+.hidden ifunc_sym
+ifunc_sym:
+ nop
+
+.global _start
+_start:
+ la.got $a0, hidden_sym
+ la.got $a1, global_sym
+ la.got $a2, undefined_sym
+ la.got $a3, ifunc_sym
+ la.got $a4, abs_sym
>From abbb058e9569a86c28505159796922aed03318f3 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Mon, 13 Jan 2025 17:53:17 +0800
Subject: [PATCH 5/6] Add comments. NFC.
---
lld/ELF/Arch/LoongArch.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp
index f5adb6555e6021..07ca66700f648f 100644
--- a/lld/ELF/Arch/LoongArch.cpp
+++ b/lld/ELF/Arch/LoongArch.cpp
@@ -809,7 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
// Note: If we can ensure that the .o files generated by LLVM only contain
// relaxable instruction sequences with R_LARCH_RELAX, then we do not need to
- // check instruction opcodes.
+ // decode instructions. The relaxable instruction sequences imply the
+ // following constraints:
+ // * For relocation pairs related to got_pc, the opcodes of instructions
+ // must be pcalau12i + ld.w/d. In other cases, the opcodes must be pcalau12i +
+ // addi.w/d.
+ // * The destination register of pcalau12i is guaranteed to be used only by
+ // the immediately following instruction.
const uint32_t nextInsn = read32le(sec.content().data() + rLo12.offset);
sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
>From cc5132f4403ea08b276d1c9bc005a7477234fc67 Mon Sep 17 00:00:00 2001
From: yangzhaoxin <yangzhaoxin at loongson.cn>
Date: Wed, 15 Jan 2025 13:56:26 +0800
Subject: [PATCH 6/6] Modify test. NFC
Dependency on https://github.com/llvm/llvm-project/pull/123017
---
lld/test/ELF/loongarch-relax-align.s | 14 +++++++-------
lld/test/ELF/loongarch-relax-emit-relocs.s | 6 +++---
.../ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s | 8 ++++----
lld/test/ELF/loongarch-relax-pc-hi20-lo12.s | 12 ++++++------
4 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/lld/test/ELF/loongarch-relax-align.s b/lld/test/ELF/loongarch-relax-align.s
index 9eaff9144d85e8..66a8ed3abf71e0 100644
--- a/lld/test/ELF/loongarch-relax-align.s
+++ b/lld/test/ELF/loongarch-relax-align.s
@@ -2,10 +2,10 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o -o %t.64
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.32.o --no-relax -o %t.32n
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.64.o --no-relax -o %t.64n
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.32.o -o %t.32n
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.64.o -o %t.64n
# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX,NOOLD %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX,NOOLD %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.32n | FileCheck --check-prefixes=NORELAX,NOOLD %s
@@ -13,13 +13,13 @@
## Test the R_LARCH_ALIGN without symbol index.
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.o64.o --defsym=old=1
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o -o %t.o64
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 %t.o64.o --no-relax -o %t.o64n
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --relax %t.o64.o -o %t.o64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.text2=0x20000 -e 0 --no-relax %t.o64.o -o %t.o64n
# RUN: llvm-objdump -td --no-show-raw-insn %t.o64 | FileCheck --check-prefixes=RELAX,OLD %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.o64n | FileCheck --check-prefixes=NORELAX,OLD %s
## -r keeps section contents unchanged.
-# RUN: ld.lld -r %t.64.o -o %t.64.r
+# RUN: ld.lld -r --relax %t.64.o -o %t.64.r
# RUN: llvm-objdump -dr --no-show-raw-insn %t.64.r | FileCheck %s --check-prefix=CHECKR
# NOOLD: {{0*}}10000 l .text {{0*}}00 .Lalign_symbol
diff --git a/lld/test/ELF/loongarch-relax-emit-relocs.s b/lld/test/ELF/loongarch-relax-emit-relocs.s
index 9f3206b7ce54ce..23d6d11786c81c 100644
--- a/lld/test/ELF/loongarch-relax-emit-relocs.s
+++ b/lld/test/ELF/loongarch-relax-emit-relocs.s
@@ -3,13 +3,13 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --mattr=+relax %s -o %t.32.o
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.64.o
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.32.o -o %t.32
-# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs %t.64.o -o %t.64
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.32.o -o %t.32
+# RUN: ld.lld -Ttext=0x10000 -section-start=.got=0x20000 --emit-relocs --relax %t.64.o -o %t.64
# RUN: llvm-objdump -dr %t.32 | FileCheck %s --check-prefix=RELAX
# RUN: llvm-objdump -dr %t.64 | FileCheck %s --check-prefix=RELAX
## -r should keep original relocations.
-# RUN: ld.lld -r %t.64.o -o %t.64.r
+# RUN: ld.lld --relax -r %t.64.o -o %t.64.r
# RUN: llvm-objdump -dr %t.64.r | FileCheck %s --check-prefix=CHECKR
## --no-relax should keep original relocations.
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
index bafb631bccb91b..0a75d2289209c2 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12-got-symbols.s
@@ -9,13 +9,13 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax abs.s -o abs.32.o
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax abs.s -o abs.64.o
-# RUN: ld.lld --shared -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
-# RUN: ld.lld --shared -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
+# RUN: ld.lld --shared --relax -Tlinker.t symbols.32.o abs.32.o -o symbols.32.so
+# RUN: ld.lld --shared --relax -Tlinker.t symbols.64.o abs.64.o -o symbols.64.so
# RUN: llvm-objdump -d --no-show-raw-insn symbols.32.so | FileCheck --check-prefixes=LIB %s
# RUN: llvm-objdump -d --no-show-raw-insn symbols.64.so | FileCheck --check-prefixes=LIB %s
-# RUN: ld.lld -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
-# RUN: ld.lld -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
+# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.32.o abs.32.o -o symbols.32
+# RUN: ld.lld --relax -Tlinker.t -z undefs symbols.64.o abs.64.o -o symbols.64
# RUN: llvm-objdump -d --no-show-raw-insn symbols.32 | FileCheck --check-prefixes=EXE %s
# RUN: llvm-objdump -d --no-show-raw-insn symbols.64 | FileCheck --check-prefixes=EXE %s
diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
index a417d89e9fa2e4..760fe77d774e30 100644
--- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
+++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s
@@ -3,18 +3,18 @@
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -o %t.32
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -o %t.64
# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.32.o -shared -o %t.32s
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 --relax %t.64.o -shared -o %t.64s
# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o
-# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.32.o -o %t.32o
+# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 --relax %t.64.o -o %t.64o
# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s
# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s
More information about the llvm-commits
mailing list