mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-21 12:56:52 +00:00
[lld][LoongArch] Relax TLS LE/GD/LD (#123600)
In local-exec form, the code sequence is converted as follows: ``` From: lu12i.w $rd, %le_hi20_r(sym) R_LARCH_TLS_LE_HI20_R, R_LARCH_RELAX add.w/d $rd, $rd, $tp, %le_add_r(sym) R_LARCH_TLS_LE_ADD_R, R_LARCH_RELAX addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym) R_LARCH_TLS_LE_LO12_R, R_LARCH_RELAX To: addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym) R_LARCH_TLS_LE_LO12_R ``` In global-dynamic or local-dynamic, the code sequence is converted as follows: ``` From: pcalau12i $a0, %ld_pc_hi20(sym) | %gd_pc_hi20(sym) R_LARCH_TLS_GD_PC_HI20 | R_LARCH_TLS_LD_PC_HI20, R_LARCH_RELAX addi.w/d $a0, $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym) R_LARCH_GOT_PC_LO12, R_LARCH_RELAX To: pcaddi $a0, %got_pc_lo12(sym) | %got_pc_lo12(sym) R_LARCH_TLS_GD_PCREL20_S2 | R_LARCH_TLS_LD_PCREL20_S2 ``` Note: For initial-exec form, since it involves the conversion from IE to LE, we will implement it in a future patch.
This commit is contained in:
parent
75f76d482c
commit
1fe702fdec
@ -154,6 +154,10 @@ static uint32_t setJ20(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xfe00001f) | (extractBits(imm, 19, 0) << 5);
|
||||
}
|
||||
|
||||
static uint32_t setJ5(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xfffffc1f) | (extractBits(imm, 4, 0) << 5);
|
||||
}
|
||||
|
||||
static uint32_t setK12(uint32_t insn, uint32_t imm) {
|
||||
return (insn & 0xffc003ff) | (extractBits(imm, 11, 0) << 10);
|
||||
}
|
||||
@ -761,10 +765,10 @@ static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
|
||||
|
||||
// Relax code sequence.
|
||||
// From:
|
||||
// pcalau12i $a0, %pc_hi20(sym)
|
||||
// addi.w/d $a0, $a0, %pc_lo12(sym)
|
||||
// pcalau12i $a0, %pc_hi20(sym) | %ld_pc_hi20(sym) | %gd_pc_hi20(sym)
|
||||
// addi.w/d $a0, $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
|
||||
// To:
|
||||
// pcaddi $a0, %pc_lo12(sym)
|
||||
// pcaddi $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
|
||||
//
|
||||
// From:
|
||||
// pcalau12i $a0, %got_pc_hi20(sym_got)
|
||||
@ -778,6 +782,10 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
|
||||
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) ||
|
||||
(rHi20.type == R_LARCH_TLS_GD_PC_HI20 &&
|
||||
rLo12.type == R_LARCH_GOT_PC_LO12) ||
|
||||
(rHi20.type == R_LARCH_TLS_LD_PC_HI20 &&
|
||||
rLo12.type == R_LARCH_GOT_PC_LO12)))
|
||||
return;
|
||||
|
||||
@ -798,6 +806,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
|
||||
else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
|
||||
rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
|
||||
dest = rHi20.sym->getVA(ctx);
|
||||
else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC)
|
||||
dest = ctx.in.got->getGlobalDynAddr(*rHi20.sym);
|
||||
else {
|
||||
Err(ctx) << getErrorLoc(ctx, (const uint8_t *)loc) << "unknown expr ("
|
||||
<< rHi20.expr << ") against symbol " << rHi20.sym
|
||||
@ -827,7 +837,12 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
|
||||
return;
|
||||
|
||||
sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
|
||||
sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
|
||||
if (rHi20.type == R_LARCH_TLS_GD_PC_HI20)
|
||||
sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_GD_PCREL20_S2;
|
||||
else if (rHi20.type == R_LARCH_TLS_LD_PC_HI20)
|
||||
sec.relaxAux->relocTypes[i + 2] = R_LARCH_TLS_LD_PCREL20_S2;
|
||||
else
|
||||
sec.relaxAux->relocTypes[i + 2] = R_LARCH_PCREL20_S2;
|
||||
sec.relaxAux->writes.push_back(insn(PCADDI, getD5(nextInsn), 0, 0));
|
||||
remove = 4;
|
||||
}
|
||||
@ -863,6 +878,33 @@ static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
|
||||
}
|
||||
}
|
||||
|
||||
// Relax code sequence.
|
||||
// From:
|
||||
// lu12i.w $rd, %le_hi20_r(sym)
|
||||
// add.w/d $rd, $rd, $tp, %le_add_r(sym)
|
||||
// addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym)
|
||||
// To:
|
||||
// addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym)
|
||||
static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i,
|
||||
uint64_t loc, Relocation &r, uint32_t &remove) {
|
||||
uint64_t val = r.sym->getVA(ctx, r.addend);
|
||||
// Check if the val exceeds the range of addi/ld/st.
|
||||
if (!isInt<12>(val))
|
||||
return;
|
||||
uint32_t currInsn = read32le(sec.content().data() + r.offset);
|
||||
switch (r.type) {
|
||||
case R_LARCH_TLS_LE_HI20_R:
|
||||
case R_LARCH_TLS_LE_ADD_R:
|
||||
sec.relaxAux->relocTypes[i] = R_LARCH_RELAX;
|
||||
remove = 4;
|
||||
break;
|
||||
case R_LARCH_TLS_LE_LO12_R:
|
||||
sec.relaxAux->writes.push_back(setJ5(currInsn, R_TP));
|
||||
sec.relaxAux->relocTypes[i] = R_LARCH_TLS_LE_LO12_R;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool relax(Ctx &ctx, InputSection &sec) {
|
||||
const uint64_t secAddr = sec.getVA();
|
||||
const MutableArrayRef<Relocation> relocs = sec.relocs();
|
||||
@ -903,6 +945,8 @@ static bool relax(Ctx &ctx, InputSection &sec) {
|
||||
}
|
||||
case R_LARCH_PCALA_HI20:
|
||||
case R_LARCH_GOT_PC_HI20:
|
||||
case R_LARCH_TLS_GD_PC_HI20:
|
||||
case R_LARCH_TLS_LD_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);
|
||||
@ -911,6 +955,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
|
||||
if (relaxable(relocs, i))
|
||||
relaxCall36(ctx, sec, i, loc, r, remove);
|
||||
break;
|
||||
case R_LARCH_TLS_LE_HI20_R:
|
||||
case R_LARCH_TLS_LE_ADD_R:
|
||||
case R_LARCH_TLS_LE_LO12_R:
|
||||
if (relaxable(relocs, i))
|
||||
relaxTlsLe(ctx, sec, i, loc, r, remove);
|
||||
break;
|
||||
}
|
||||
|
||||
// For all anchors whose offsets are <= r.offset, they are preceded by
|
||||
@ -1015,9 +1065,22 @@ void LoongArch::finalizeRelax(int passes) const {
|
||||
r.expr = r.sym->hasFlag(NEEDS_PLT) ? R_PLT_PC : R_PC;
|
||||
break;
|
||||
case R_LARCH_B26:
|
||||
case R_LARCH_TLS_LE_LO12_R:
|
||||
skip = 4;
|
||||
write32le(p, aux.writes[writesIdx++]);
|
||||
break;
|
||||
case R_LARCH_TLS_GD_PCREL20_S2:
|
||||
// Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead
|
||||
// of R_TLSLD_PC due to historical reasons. In fact, right now TLSLD
|
||||
// behaves exactly like TLSGD on LoongArch.
|
||||
//
|
||||
// This reason has also been mentioned in mold commit:
|
||||
// https://github.com/rui314/mold/commit/5dfa1cf07c03bd57cb3d493b652ef22441bcd71c
|
||||
case R_LARCH_TLS_LD_PCREL20_S2:
|
||||
skip = 4;
|
||||
write32le(p, aux.writes[writesIdx++]);
|
||||
r.expr = R_TLSGD_PC;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unsupported type");
|
||||
}
|
||||
|
@ -27,10 +27,6 @@
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: R_LARCH_PCREL20_S2 _start
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX32-NEXT: nop
|
||||
# RELAX32-NEXT: R_LARCH_ALIGN *ABS*+0xc
|
||||
# RELAX32-NEXT: nop
|
||||
# RELAX32-NEXT: ret
|
||||
|
||||
# RELAX64-NEXT: bl -8
|
||||
# RELAX64-NEXT: R_LARCH_B26 _start
|
||||
@ -38,8 +34,38 @@
|
||||
# RELAX64-NEXT: b -12
|
||||
# RELAX64-NEXT: R_LARCH_B26 _start
|
||||
# RELAX64-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX64-NEXT: ret
|
||||
|
||||
# RELAX-NEXT: lu12i.w $a0, 0
|
||||
# RELAX-NEXT: R_LARCH_TLS_LE_HI20 a
|
||||
# RELAX-NEXT: ori $a0, $a0, 0
|
||||
# RELAX-NEXT: R_LARCH_TLS_LE_LO12 a
|
||||
# RELAX-NEXT: pcaddi $a0, [[#]]
|
||||
# RELAX-NEXT: R_LARCH_RELAX a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: R_LARCH_TLS_GD_PCREL20_S2 a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: pcaddi $a0, [[#]]
|
||||
# RELAX-NEXT: R_LARCH_RELAX a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: R_LARCH_TLS_LD_PCREL20_S2 a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: addi.{{[dw]}} $a0, $tp, 0
|
||||
# RELAX-NEXT: R_LARCH_RELAX a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: R_LARCH_RELAX a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# RELAX-NEXT: R_LARCH_TLS_LE_LO12_R a
|
||||
# RELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
|
||||
# RELAX32-NEXT: nop
|
||||
# RELAX32-NEXT: R_LARCH_ALIGN *ABS*+0xc
|
||||
# RELAX32-NEXT: ret
|
||||
|
||||
# RELAX64-NEXT: nop
|
||||
# RELAX64-NEXT: R_LARCH_ALIGN *ABS*+0xc
|
||||
# RELAX64-NEXT: nop
|
||||
# RELAX64-NEXT: nop
|
||||
# RELAX64-NEXT: ret
|
||||
|
||||
# NORELAX: <_start>:
|
||||
# NORELAX-NEXT: pcalau12i $a0, 0
|
||||
@ -62,8 +88,36 @@
|
||||
# NORELAX-NEXT: R_LARCH_CALL36 _start
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: jirl $zero, $a0, -24
|
||||
# NORELAX-NEXT: ret
|
||||
# NORELAX-NEXT: lu12i.w $a0, 0
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LE_HI20 a
|
||||
# NORELAX-NEXT: ori $a0, $a0, 0
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LE_LO12 a
|
||||
# NORELAX-NEXT: pcalau12i $a0, 16
|
||||
# NORELAX-NEXT: R_LARCH_TLS_GD_PC_HI20 a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: addi.d $a0, $a0, 8
|
||||
# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: pcalau12i $a0, 16
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LD_PC_HI20 a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: addi.d $a0, $a0, 8
|
||||
# NORELAX-NEXT: R_LARCH_GOT_PC_LO12 a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: lu12i.w $a0, 0
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LE_HI20_R a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: add.d $a0, $a0, $tp
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LE_ADD_R a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: addi.d $a0, $a0, 0
|
||||
# NORELAX-NEXT: R_LARCH_TLS_LE_LO12_R a
|
||||
# NORELAX-NEXT: R_LARCH_RELAX *ABS*
|
||||
# NORELAX-NEXT: nop
|
||||
# NORELAX-NEXT: R_LARCH_ALIGN *ABS*+0xc
|
||||
# NORELAX-NEXT: nop
|
||||
# NORELAX-NEXT: nop
|
||||
# NORELAX-NEXT: ret
|
||||
|
||||
# CHECKR: <_start>:
|
||||
# CHECKR-NEXT: pcalau12i $a0, 0
|
||||
@ -86,12 +140,53 @@
|
||||
# CHECKR-NEXT: R_LARCH_CALL36 _start
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: jr $a0
|
||||
# CHECKR-NEXT: lu12i.w $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LE_HI20 a
|
||||
# CHECKR-NEXT: ori $a0, $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LE_LO12 a
|
||||
# CHECKR-NEXT: pcalau12i $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_GD_PC_HI20 a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: addi.d $a0, $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: pcalau12i $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LD_PC_HI20 a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: addi.d $a0, $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_GOT_PC_LO12 a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: lu12i.w $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LE_HI20_R a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: add.d $a0, $a0, $tp
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LE_ADD_R a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: addi.d $a0, $a0, 0
|
||||
# CHECKR-NEXT: R_LARCH_TLS_LE_LO12_R a
|
||||
# CHECKR-NEXT: R_LARCH_RELAX *ABS*
|
||||
# CHECKR-NEXT: nop
|
||||
# CHECKR-NEXT: R_LARCH_ALIGN *ABS*+0xc
|
||||
# CHECKR-NEXT: nop
|
||||
# CHECKR-NEXT: nop
|
||||
# CHECKR-NEXT: ret
|
||||
|
||||
.macro add dst, src1, src2, src3
|
||||
.ifdef ELF64
|
||||
add.d \dst, \src1, \src2, \src3
|
||||
.else
|
||||
add.w \dst, \src1, \src2, \src3
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro addi dst, src1, src2
|
||||
.ifdef ELF64
|
||||
addi.d \dst, \src1, \src2
|
||||
.else
|
||||
addi.w \dst, \src1, \src2
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
la.pcrel $a0, _start
|
||||
@ -101,5 +196,19 @@ _start:
|
||||
call36 _start
|
||||
tail36 $a0, _start
|
||||
.endif
|
||||
|
||||
la.tls.le $a0, a # without R_LARCH_RELAX reloaction
|
||||
la.tls.gd $a0, a
|
||||
la.tls.ld $a0, a
|
||||
|
||||
lu12i.w $a0, %le_hi20_r(a)
|
||||
add $a0, $a0, $tp, %le_add_r(a)
|
||||
addi $a0, $a0, %le_lo12_r(a)
|
||||
|
||||
.p2align 4
|
||||
ret
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.globl a
|
||||
a:
|
||||
.zero 4
|
||||
|
115
lld/test/ELF/loongarch-relax-tls-le.s
Normal file
115
lld/test/ELF/loongarch-relax-tls-le.s
Normal file
@ -0,0 +1,115 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax --defsym ELF32=1 %s -o %t.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o
|
||||
|
||||
# RUN: ld.lld %t.32.o -o %t.32
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX32 %s
|
||||
|
||||
# RUN: ld.lld %t.64.o -o %t.64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX64 %s
|
||||
|
||||
# RELAX32-LABEL: <_start>:
|
||||
## .LANCHOR0@tprel = 8
|
||||
# RELAX32-NEXT: addi.w $a0, $tp, 8
|
||||
# RELAX32-NEXT: ld.w $a1, $a0, 0
|
||||
# RELAX32-NEXT: ld.w $a2, $tp, 8
|
||||
## .a@tprel - 4 = 0x7fc
|
||||
# RELAX32-NEXT: addi.w $a1, $zero, 1
|
||||
# RELAX32-NEXT: addi.w $a1, $a1, 2
|
||||
# RELAX32-NEXT: st.w $a1, $tp, 2044
|
||||
## .a@tprel = 0x800
|
||||
# RELAX32-NEXT: lu12i.w $a0, 1
|
||||
# RELAX32-NEXT: add.w $a0, $a0, $tp
|
||||
# RELAX32-NEXT: addi.w $a0, $a0, -2048
|
||||
|
||||
# RELAX64-LABEL: <_start>:
|
||||
## .LANCHOR0@tprel = 8
|
||||
# RELAX64-NEXT: addi.d $a0, $tp, 8
|
||||
# RELAX64-NEXT: ld.d $a1, $a0, 0
|
||||
# RELAX64-NEXT: ld.d $a2, $tp, 8
|
||||
## .a@tprel - 4 = 0x7fc
|
||||
# RELAX64-NEXT: addi.d $a1, $zero, 1
|
||||
# RELAX64-NEXT: addi.d $a1, $a1, 2
|
||||
# RELAX64-NEXT: st.d $a1, $tp, 2044
|
||||
## .a@tprel = 0x800
|
||||
# RELAX64-NEXT: lu12i.w $a0, 1
|
||||
# RELAX64-NEXT: add.d $a0, $a0, $tp
|
||||
# RELAX64-NEXT: addi.d $a0, $a0, -2048
|
||||
|
||||
.macro add dst, src1, src2, src3
|
||||
.ifdef ELF32
|
||||
add.w \dst, \src1, \src2, \src3
|
||||
.else
|
||||
add.d \dst, \src1, \src2, \src3
|
||||
.endif
|
||||
.endm
|
||||
.macro inst op dst, src1, src2
|
||||
.ifdef ELF32
|
||||
.ifc \op, addi
|
||||
addi.w \dst, \src1, \src2
|
||||
.else; .ifc \op, ld
|
||||
ld.w \dst, \src1, \src2
|
||||
.else; .ifc \op, st
|
||||
st.w \dst, \src1, \src2
|
||||
.else; .ifc \op, ldptr
|
||||
ldptr.w \dst, \src1, \src2
|
||||
.else
|
||||
.error "Unknown op in ELF32 mode"
|
||||
.endif; .endif; .endif; .endif
|
||||
.else
|
||||
.ifc \op, addi
|
||||
addi.d \dst, \src1, \src2
|
||||
.else; .ifc \op, ld
|
||||
ld.d \dst, \src1, \src2
|
||||
.else; .ifc \op, st
|
||||
st.d \dst, \src1, \src2
|
||||
.else; .ifc \op, ldptr
|
||||
ldptr.d \dst, \src1, \src2
|
||||
.else
|
||||
.error "Unknown op in ELF64 mode"
|
||||
.endif; .endif; .endif; .endif
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro addi dst, src1, src2
|
||||
inst addi \dst, \src1, \src2
|
||||
.endm
|
||||
.macro ld dst, src1, src2
|
||||
inst ld \dst, \src1, \src2
|
||||
.endm
|
||||
.macro st dst, src1, src2
|
||||
inst st \dst, \src1, \src2
|
||||
.endm
|
||||
.macro ldptr dst, src1, src2
|
||||
inst ldptr \dst, \src1, \src2
|
||||
.endm
|
||||
|
||||
_start:
|
||||
## Test instructions not in pairs.
|
||||
lu12i.w $a0, %le_hi20_r(.LANCHOR0)
|
||||
add $a0, $a0, $tp, %le_add_r(.LANCHOR0)
|
||||
addi $a0, $a0, %le_lo12_r(.LANCHOR0)
|
||||
ld $a1, $a0, 0
|
||||
ld $a2, $a0, %le_lo12_r(.LANCHOR0)
|
||||
|
||||
## hi20(a-4) = hi20(0x7fc) = 0. relaxable
|
||||
## Test non-adjacent instructions.
|
||||
lu12i.w $a0, %le_hi20_r(a-4)
|
||||
addi $a1, $zero, 0x1
|
||||
add $a0, $a0, $tp, %le_add_r(a-4)
|
||||
addi $a1, $a1, 0x2
|
||||
st $a1, $a0, %le_lo12_r(a-4)
|
||||
|
||||
## hi20(a) = hi20(0x800) = 1. not relaxable
|
||||
lu12i.w $a0, %le_hi20_r(a)
|
||||
add $a0, $a0, $tp, %le_add_r(a)
|
||||
addi $a0, $a0, %le_lo12_r(a)
|
||||
|
||||
.section .tbss,"awT",@nobits
|
||||
.space 8
|
||||
.LANCHOR0:
|
||||
.space 0x800-8
|
||||
.globl a
|
||||
a:
|
||||
.zero 4
|
@ -1,14 +1,17 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
|
||||
## relaxed, dynamic relocations can be omitted for GD->LE relaxation.
|
||||
## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc:
|
||||
## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
|
||||
## (b) dynamic relocations can be omitted for GD->LE relaxation.
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/a.s -o %t/a.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %t/a.s -o %t/a.32.relax.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/bc.s -o %t/bc.32.o
|
||||
# RUN: ld.lld -shared -soname=bc.so %t/bc.32.o -o %t/bc.32.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -o %t/a.64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/a.s -mattr=+relax -o %t/a.64.relax.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/bc.s -o %t/bc.64.o
|
||||
# RUN: ld.lld -shared -soname=bc.so %t/bc.64.o -o %t/bc.64.so
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
|
||||
@ -17,6 +20,9 @@
|
||||
# RUN: ld.lld -shared %t/a.32.o %t/bc.32.o -o %t/gd.32.so
|
||||
# RUN: llvm-readobj -r %t/gd.32.so | FileCheck --check-prefix=GD32-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.so | FileCheck --check-prefix=GD32 %s
|
||||
# RUN: ld.lld -shared %t/a.32.relax.o %t/bc.32.o -o %t/gd.32.relax.so
|
||||
# RUN: llvm-readobj -r %t/gd.32.relax.so | FileCheck --check-prefix=GD32-REL-RELAX %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.32.relax.so | FileCheck --check-prefix=GD32-RELAX %s
|
||||
|
||||
## LA32 GD -> LE
|
||||
# RUN: ld.lld %t/a.32.o %t/bc.32.o %t/tga.32.o -o %t/le.32
|
||||
@ -35,6 +41,9 @@
|
||||
# RUN: ld.lld -shared %t/a.64.o %t/bc.64.o -o %t/gd.64.so
|
||||
# RUN: llvm-readobj -r %t/gd.64.so | FileCheck --check-prefix=GD64-REL %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.so | FileCheck --check-prefix=GD64 %s
|
||||
# RUN: ld.lld -shared %t/a.64.relax.o %t/bc.64.o -o %t/gd.64.relax.so
|
||||
# RUN: llvm-readobj -r %t/gd.64.relax.so | FileCheck --check-prefix=GD64-REL-RELAX %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/gd.64.relax.so | FileCheck --check-prefix=GD64-RELAX %s
|
||||
|
||||
## LA64 GD -> LE
|
||||
# RUN: ld.lld %t/a.64.o %t/bc.64.o %t/tga.64.o -o %t/le.64
|
||||
@ -66,6 +75,21 @@
|
||||
# GD32-NEXT: addi.w $a0, $a0, 792
|
||||
# GD32-NEXT: bl 44
|
||||
|
||||
# GD32-REL-RELAX: .rela.dyn {
|
||||
# GD32-REL-RELAX-NEXT: 0x20300 R_LARCH_TLS_DTPMOD32 a 0x0
|
||||
# GD32-REL-RELAX-NEXT: 0x20304 R_LARCH_TLS_DTPREL32 a 0x0
|
||||
# GD32-REL-RELAX-NEXT: 0x20308 R_LARCH_TLS_DTPMOD32 b 0x0
|
||||
# GD32-REL-RELAX-NEXT: 0x2030C R_LARCH_TLS_DTPREL32 b 0x0
|
||||
# GD32-REL-RELAX-NEXT: }
|
||||
|
||||
## &DTPMOD(a) - . = 0x20300 - 0x10250 = 16428<<2
|
||||
# GD32-RELAX: 10250: pcaddi $a0, 16428
|
||||
# GD32-RELAX-NEXT: bl 44
|
||||
|
||||
## &DTPMOD(b) - . = 0x20308 - 0x10258 = 16428<<2
|
||||
# GD32-RELAX: 10258: pcaddi $a0, 16428
|
||||
# GD32-RELAX-NEXT: bl 36
|
||||
|
||||
# GD64-REL: .rela.dyn {
|
||||
# GD64-REL-NEXT: 0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0
|
||||
# GD64-REL-NEXT: 0x204C8 R_LARCH_TLS_DTPREL64 a 0x0
|
||||
@ -83,6 +107,21 @@
|
||||
# GD64-NEXT: addi.d $a0, $a0, 1232
|
||||
# GD64-NEXT: bl 36
|
||||
|
||||
# GD64-REL-RELAX: .rela.dyn {
|
||||
# GD64-REL-RELAX-NEXT: 0x204C0 R_LARCH_TLS_DTPMOD64 a 0x0
|
||||
# GD64-REL-RELAX-NEXT: 0x204C8 R_LARCH_TLS_DTPREL64 a 0x0
|
||||
# GD64-REL-RELAX-NEXT: 0x204D0 R_LARCH_TLS_DTPMOD64 b 0x0
|
||||
# GD64-REL-RELAX-NEXT: 0x204D8 R_LARCH_TLS_DTPREL64 b 0x0
|
||||
# GD64-REL-RELAX-NEXT: }
|
||||
|
||||
## &DTPMOD(a) - . = 0x204c0 - 0x10398 = 16458<<2
|
||||
# GD64-RELAX: 10398: pcaddi $a0, 16458
|
||||
# GD64-RELAX-NEXT: bl 52
|
||||
|
||||
## &DTPMOD(b) - . = 0x204d0 - 0x103a0 = 16460<<2
|
||||
# GD64-RELAX: 103a0: pcaddi $a0, 16460
|
||||
# GD64-RELAX-NEXT: bl 44
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel]
|
||||
|
@ -1,12 +1,15 @@
|
||||
# REQUIRES: loongarch
|
||||
# RUN: rm -rf %t && split-file %s %t
|
||||
|
||||
## LoongArch psABI doesn't specify TLS relaxation. Though the code sequences are not
|
||||
## relaxed, dynamic relocations can be omitted for LD->LE relaxation.
|
||||
## LoongArch psABI doesn't specify TLS relaxation. It can be handled the same way as gcc:
|
||||
## (a) code sequence can be converted from `pcalau12i+addi.[wd]` to `pcaddi`.
|
||||
## (b) dynamic relocations can be omitted for LD->LE relaxation.
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent %t/a.s -o %t/a.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --position-independent -mattr=+relax %t/a.s -o %t/a.32.relax.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 %t/tga.s -o %t/tga.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent %t/a.s -o %t/a.64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --position-independent -mattr=+relax %t/a.s -o %t/a.64.relax.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %t/tga.s -o %t/tga.64.o
|
||||
|
||||
## LA32 LD
|
||||
@ -14,24 +17,34 @@
|
||||
# RUN: llvm-readobj -r %t/ld.32.so | FileCheck --check-prefix=LD32-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ld.32.so | FileCheck --check-prefix=LD32-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.so | FileCheck --check-prefixes=LD32 %s
|
||||
# RUN: ld.lld -shared %t/a.32.relax.o -o %t/ld.32.relax.so
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.32.relax.so | FileCheck --check-prefixes=LD32-RELAX %s
|
||||
|
||||
## LA32 LD -> LE
|
||||
# RUN: ld.lld %t/a.32.o %t/tga.32.o -o %t/le.32
|
||||
# RUN: llvm-readelf -r %t/le.32 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.32 | FileCheck --check-prefix=LE32-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.32 | FileCheck --check-prefixes=LE32 %s
|
||||
# RUN: ld.lld %t/a.32.relax.o %t/tga.32.o -o %t/le.32.relax
|
||||
# RUN: llvm-readelf -x .got %t/le.32.relax | FileCheck --check-prefix=LE32-GOT-RELAX %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.32.relax | FileCheck --check-prefixes=LE32-RELAX %s
|
||||
|
||||
## LA64 LD
|
||||
# RUN: ld.lld -shared %t/a.64.o -o %t/ld.64.so
|
||||
# RUN: llvm-readobj -r %t/ld.64.so | FileCheck --check-prefix=LD64-REL %s
|
||||
# RUN: llvm-readelf -x .got %t/ld.64.so | FileCheck --check-prefix=LD64-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.so | FileCheck --check-prefixes=LD64 %s
|
||||
# RUN: ld.lld -shared %t/a.64.relax.o -o %t/ld.64.relax.so
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/ld.64.relax.so | FileCheck --check-prefixes=LD64-RELAX %s
|
||||
|
||||
## LA64 LD -> LE
|
||||
# RUN: ld.lld %t/a.64.o %t/tga.64.o -o %t/le.64
|
||||
# RUN: llvm-readelf -r %t/le.64 | FileCheck --check-prefix=NOREL %s
|
||||
# RUN: llvm-readelf -x .got %t/le.64 | FileCheck --check-prefix=LE64-GOT %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.64 | FileCheck --check-prefixes=LE64 %s
|
||||
# RUN: ld.lld %t/a.64.relax.o %t/tga.64.o -o %t/le.64.relax
|
||||
# RUN: llvm-readelf -x .got %t/le.64.relax | FileCheck --check-prefix=LE64-GOT-RELAX %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t/le.64.relax | FileCheck --check-prefixes=LE64-RELAX %s
|
||||
|
||||
## a@dtprel = st_value(a) = 0 is a link-time constant.
|
||||
# LD32-REL: .rela.dyn {
|
||||
@ -56,6 +69,14 @@
|
||||
# LD64-NEXT: addi.d $a0, $a0, 1024
|
||||
# LD64-NEXT: bl 40
|
||||
|
||||
## LA32: &DTPMOD(a) - . = 0x20280 - 0x101cc = 16429<<2
|
||||
# LD32-RELAX: 101cc: pcaddi $a0, 16429
|
||||
# LD32-RELAX-NEXT: bl 48
|
||||
|
||||
## LA64: &DTPMOD(a) - . = 0x20400 - 0x102e0 = 16456<<2
|
||||
# LD64-RELAX: 102e0: pcaddi $a0, 16456
|
||||
# LD64-RELAX-NEXT: bl 44
|
||||
|
||||
# NOREL: no relocations
|
||||
|
||||
## a is local - its DTPMOD/DTPREL slots are link-time constants.
|
||||
@ -66,6 +87,12 @@
|
||||
# LE64-GOT: section '.got':
|
||||
# LE64-GOT-NEXT: 0x000301d8 01000000 00000000 00000000 00000000
|
||||
|
||||
# LE32-GOT-RELAX: section '.got':
|
||||
# LE32-GOT-RELAX-NEXT: 0x0003011c 01000000 00000000
|
||||
|
||||
# LE64-GOT-RELAX: section '.got':
|
||||
# LE64-GOT-RELAX-NEXT: 0x000301d0 01000000 00000000 00000000 00000000
|
||||
|
||||
## LA32: DTPMOD(.LANCHOR0) - . = 0x30120 - 0x20114: 0x10 pages, page offset 0x120
|
||||
# LE32: 20114: pcalau12i $a0, 16
|
||||
# LE32-NEXT: addi.w $a0, $a0, 288
|
||||
@ -76,6 +103,15 @@
|
||||
# LE64-NEXT: addi.d $a0, $a0, 472
|
||||
# LE64-NEXT: bl 4
|
||||
|
||||
## LA32: DTPMOD(.LANCHOR0) - . = 0x3011c - 0x20114 = 16386<<2
|
||||
# LE32-RELAX: 20114: pcaddi $a0, 16386
|
||||
# LE32-RELAX-NEXT: bl 4
|
||||
|
||||
## LA64: DTPMOD(.LANCHOR0) - . = 0x301d0 - 0x201c8 = 16386<<2
|
||||
# LE64-RELAX: 201c8: pcaddi $a0, 16386
|
||||
# LE64-RELAX-NEXT: bl 4
|
||||
|
||||
|
||||
#--- a.s
|
||||
la.tls.ld $a0, .LANCHOR0
|
||||
bl %plt(__tls_get_addr)
|
||||
|
@ -1,14 +1,20 @@
|
||||
# REQUIRES: loongarch
|
||||
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 %s -o %t.32.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch32 --defsym ELF32=1 -mattr=+relax %s -o %t.32.relax.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s -o %t.64.o
|
||||
# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.relax.o
|
||||
|
||||
# RUN: ld.lld %t.32.o -o %t.32
|
||||
# RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
|
||||
# RUN: ld.lld %t.32.relax.o -o %t.32.relax
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.32.relax | FileCheck --check-prefixes=LE,LE32-RELAX %s
|
||||
|
||||
# RUN: ld.lld %t.64.o -o %t.64
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
|
||||
# RUN: ld.lld %t.64.relax.o -o %t.64.relax
|
||||
# RUN: llvm-objdump -d --no-show-raw-insn %t.64.relax | FileCheck --check-prefixes=LE,LE64-RELAX %s
|
||||
|
||||
# RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
|
||||
|
||||
@ -37,12 +43,22 @@
|
||||
# LE32-NEXT: add.w $a0, $a0, $tp
|
||||
# LE32-NEXT: addi.w $a0, $a0, -2048
|
||||
|
||||
# LE32-RELAX: addi.w $a0, $tp, 8
|
||||
# LE32-RELAX-NEXT: lu12i.w $a0, 1
|
||||
# LE32-RELAX-NEXT: add.w $a0, $a0, $tp
|
||||
# LE32-RELAX-NEXT: addi.w $a0, $a0, -2048
|
||||
|
||||
# LE64: add.d $a0, $a0, $tp
|
||||
# LE64-NEXT: addi.d $a0, $a0, 8
|
||||
# LE64-NEXT: lu12i.w $a0, 1
|
||||
# LE64-NEXT: add.d $a0, $a0, $tp
|
||||
# LE64-NEXT: addi.d $a0, $a0, -2048
|
||||
|
||||
# LE64-RELAX: addi.d $a0, $tp, 8
|
||||
# LE64-RELAX-NEXT: lu12i.w $a0, 1
|
||||
# LE64-RELAX-NEXT: add.d $a0, $a0, $tp
|
||||
# LE64-RELAX-NEXT: addi.d $a0, $a0, -2048
|
||||
|
||||
# LE-EMPTY:
|
||||
|
||||
.macro add dst, src1, src2, src3
|
||||
|
Loading…
x
Reference in New Issue
Block a user