Skip to content

Commit a39c190

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 d5c9d64 commit a39c190

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,
@@ -1000,6 +1006,87 @@ static bool relax(Ctx &ctx, InputSection &sec) {
10001006
return changed;
10011007
}
10021008

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

1346+
// LoongArch support IE to LE optimization in non-extreme code model.
1347+
bool execOptimizeInLoongArch =
1348+
ctx.arg.emachine == EM_LOONGARCH &&
1349+
(type == R_LARCH_TLS_IE_PC_HI20 || type == R_LARCH_TLS_IE_PC_LO12);
1350+
13461351
// ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE
13471352
// optimizations.
13481353
// RISC-V supports TLSDESC to IE/LE optimizations.
13491354
// For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
13501355
// optimization as well.
13511356
bool execOptimize =
13521357
!ctx.arg.shared && ctx.arg.emachine != EM_ARM &&
1353-
ctx.arg.emachine != EM_HEXAGON && ctx.arg.emachine != EM_LOONGARCH &&
1358+
ctx.arg.emachine != EM_HEXAGON && execOptimizeInLoongArch &&
13541359
!(isRISCV && expr != R_TLSDESC_PC && expr != R_TLSDESC_CALL) &&
13551360
!sec->file->ppc64DisableTLSRelax;
13561361

@@ -1425,6 +1430,14 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
14251430
return ctx.target->getTlsGdRelaxSkip(type);
14261431
}
14271432

1433+
// LoongArch TLS GD/LD relocs reuse the RE_LOONGARCH_TLSGD_PAGE_PC, in which
1434+
// NEEDS_TLSIE shouldn't set. So we check independently.
1435+
if (ctx.arg.emachine == EM_LOONGARCH && expr == RE_LOONGARCH_GOT &&
1436+
execOptimize && isLocalInExecutable) {
1437+
sec->addReloc({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
1438+
return 1;
1439+
}
1440+
14281441
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, RE_AARCH64_GOT_PAGE_PC,
14291442
RE_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF, R_TLSIE_HINT>(expr)) {
14301443
ctx.hasTlsIe.store(true, std::memory_order_relaxed);

0 commit comments

Comments
 (0)