Skip to content

Commit 0f58056

Browse files
committed
Convert TLS IE to LE in the normal or medium code model.
Original code sequence: * pcalau12i $a0, %ie_pc_hi20(sym) * ld.d $a0, $a0, %ie_pc_lo12(sym) The code sequence converted is as follows: * lu12i.w $a0, %ie_pc_hi20(sym) # le_hi20 != 0, otherwise NOP * ori $a0 $a0, %ie_pc_lo12(sym) FIXME: When relaxation enables, redundant NOP can be removed. This will be implemented in a future patch. Note: In the normal or medium code model, original code sequence with relocations can appear interleaved, because converted code sequence calculates the absolute offset. However, in extreme code model, to identify the current code model, the first four instructions with relocations must appear consecutively.
1 parent 9d29d9b commit 0f58056

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ class LoongArch final : public TargetInfo {
3939
void relocate(uint8_t *loc, const Relocation &rel,
4040
uint64_t val) const override;
4141
bool relaxOnce(int pass) const override;
42+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
4243
void finalizeRelax(int passes) const override;
44+
45+
private:
46+
void tlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
4347
};
4448
} // end anonymous namespace
4549

@@ -53,6 +57,8 @@ enum Op {
5357
ADDI_W = 0x02800000,
5458
ADDI_D = 0x02c00000,
5559
ANDI = 0x03400000,
60+
ORI = 0x03800000,
61+
LU12I_W = 0x14000000,
5662
PCADDI = 0x18000000,
5763
PCADDU12I = 0x1c000000,
5864
LD_W = 0x28800000,
@@ -1002,6 +1008,87 @@ static bool relax(Ctx &ctx, InputSection &sec) {
10021008
return changed;
10031009
}
10041010

1011+
// Convert TLS IE to LE in the normal or medium code model.
1012+
// Original code sequence:
1013+
// * pcalau12i $a0, %ie_pc_hi20(sym)
1014+
// * ld.d $a0, $a0, %ie_pc_lo12(sym)
1015+
//
1016+
// The code sequence converted is as follows:
1017+
// * lu12i.w $a0, %le_hi20(sym) # le_hi20 != 0, otherwise NOP
1018+
// * ori $a0 $a0, %le_lo12(sym)
1019+
//
1020+
// When relaxation enables, redundant NOPs can be removed.
1021+
void LoongArch::tlsIeToLe(uint8_t *loc, const Relocation &rel,
1022+
uint64_t val) const {
1023+
assert(isInt<32>(val) &&
1024+
"val exceeds the range of medium code model in tlsIeToLe");
1025+
1026+
bool isUInt12 = isUInt<12>(val);
1027+
const uint32_t currInsn = read32le(loc);
1028+
switch (rel.type) {
1029+
case R_LARCH_TLS_IE_PC_HI20:
1030+
if (isUInt12)
1031+
write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop
1032+
else
1033+
write32le(loc, insn(LU12I_W, getD5(currInsn), extractBits(val, 31, 12),
1034+
0)); // lu12i.w $a0, %le_hi20
1035+
break;
1036+
case R_LARCH_TLS_IE_PC_LO12:
1037+
if (isUInt12)
1038+
write32le(loc, insn(ORI, getD5(currInsn), R_ZERO,
1039+
val)); // ori $a0, $r0, %le_lo12
1040+
else
1041+
write32le(loc, insn(ORI, getD5(currInsn), getJ5(currInsn),
1042+
lo12(val))); // ori $a0, $a0, %le_lo12
1043+
break;
1044+
}
1045+
}
1046+
1047+
void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
1048+
const unsigned bits = ctx.arg.is64 ? 64 : 32;
1049+
uint64_t secAddr = sec.getOutputSection()->addr;
1050+
if (auto *s = dyn_cast<InputSection>(&sec))
1051+
secAddr += s->outSecOff;
1052+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
1053+
secAddr += ehIn->getParent()->outSecOff;
1054+
bool isExtreme = false;
1055+
const MutableArrayRef<Relocation> relocs = sec.relocs();
1056+
for (size_t i = 0, size = relocs.size(); i != size; ++i) {
1057+
Relocation &rel = relocs[i];
1058+
uint8_t *loc = buf + rel.offset;
1059+
uint64_t val = SignExtend64(
1060+
sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset), bits);
1061+
1062+
switch (rel.expr) {
1063+
case R_RELAX_HINT:
1064+
continue;
1065+
case R_RELAX_TLS_IE_TO_LE:
1066+
if (rel.type == R_LARCH_TLS_IE_PC_HI20) {
1067+
// LoongArch does not support IE to LE optimize in the extreme code
1068+
// model. In this case, the relocs are as follows:
1069+
//
1070+
// * i -- R_LARCH_TLS_IE_PC_HI20
1071+
// * i+1 -- R_LARCH_TLS_IE_PC_LO12
1072+
// * i+2 -- R_LARCH_TLS_IE64_PC_LO20
1073+
// * i+3 -- R_LARCH_TLS_IE64_PC_HI12
1074+
isExtreme =
1075+
(i + 2 < size && relocs[i + 2].type == R_LARCH_TLS_IE64_PC_LO20);
1076+
}
1077+
if (isExtreme) {
1078+
rel.expr = getRelExpr(rel.type, *rel.sym, loc);
1079+
val = SignExtend64(sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset),
1080+
bits);
1081+
relocateNoSym(loc, rel.type, val);
1082+
} else
1083+
tlsIeToLe(loc, rel, val);
1084+
continue;
1085+
default:
1086+
break;
1087+
}
1088+
relocate(loc, rel, val);
1089+
}
1090+
}
1091+
10051092
// When relaxing just R_LARCH_ALIGN, relocDeltas is usually changed only once in
10061093
// the absence of a linker script. For call and load/store R_LARCH_RELAX, code
10071094
// shrinkage may reduce displacement and make more relocations eligible for

lld/ELF/Relocations.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,14 +1375,19 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
13751375
return 1;
13761376
}
13771377

1378+
// LoongArch support IE to LE optimization in non-extreme code model.
1379+
bool execOptimizeInLoongArch =
1380+
ctx.arg.emachine == EM_LOONGARCH &&
1381+
(type == R_LARCH_TLS_IE_PC_HI20 || type == R_LARCH_TLS_IE_PC_LO12);
1382+
13781383
// ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE
13791384
// optimizations.
13801385
// RISC-V supports TLSDESC to IE/LE optimizations.
13811386
// For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
13821387
// optimization as well.
13831388
bool execOptimize =
13841389
!ctx.arg.shared && ctx.arg.emachine != EM_ARM &&
1385-
ctx.arg.emachine != EM_HEXAGON && ctx.arg.emachine != EM_LOONGARCH &&
1390+
ctx.arg.emachine != EM_HEXAGON && execOptimizeInLoongArch &&
13861391
!(isRISCV && expr != R_TLSDESC_PC && expr != R_TLSDESC_CALL) &&
13871392
!sec->file->ppc64DisableTLSRelax;
13881393

@@ -1457,6 +1462,14 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
14571462
return ctx.target->getTlsGdRelaxSkip(type);
14581463
}
14591464

1465+
// LoongArch TLS GD/LD relocs reuse the RE_LOONGARCH_TLSGD_PAGE_PC, in which
1466+
// NEEDS_TLSIE shouldn't set. So we check independently.
1467+
if (ctx.arg.emachine == EM_LOONGARCH && expr == RE_LOONGARCH_GOT &&
1468+
execOptimize && isLocalInExecutable) {
1469+
sec->addReloc({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
1470+
return 1;
1471+
}
1472+
14601473
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, RE_AARCH64_GOT_PAGE_PC,
14611474
RE_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF, R_TLSIE_HINT>(expr)) {
14621475
ctx.hasTlsIe.store(true, std::memory_order_relaxed);

0 commit comments

Comments
 (0)