[lld] [lld][LoongArch] Support TLSDESC GD/LD to IE/LE (PR #123715)
Jinyang He via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 24 11:04:07 PDT 2025
================
@@ -1046,6 +1054,103 @@ static void tlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
}
}
+// Convert TLSDESC GD/LD to IE.
+// In normal or medium code model, there are two forms of code sequences:
+// * pcalau12i $a0, %desc_pc_hi20(sym_desc)
+// * addi.d $a0, $a0, %desc_pc_lo12(sym_desc)
+// * ld.d $ra, $a0, %desc_ld(sym_desc)
+// * jirl $ra, $ra, %desc_call(sym_desc)
+// ------
+// * pcaddi $a0, %desc_pcrel_20(a)
+// * load $ra, $a0, %desc_ld(a)
+// * jirl $ra, $ra, %desc_call(a)
+//
+// The code sequence obtained is as follows:
+// * pcalau12i $a0, %ie_pc_hi20(sym_ie)
+// * ld.[wd] $a0, $a0, %ie_pc_lo12(sym_ie)
+//
+// Simplicity, whether tlsdescToIe or tlsdescToLe, we always tend to convert the
+// preceding instructions to NOPs, due to both forms of code sequence
+// (corresponding to relocation combinations:
+// R_LARCH_TLS_DESC_PC_HI20+R_LARCH_TLS_DESC_PC_LO12 and
+// R_LARCH_TLS_DESC_PCREL20_S2) have same process.
+//
+// When relaxation enables, redundant NOPs can be removed.
+void LoongArch::tlsdescToIe(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ switch (rel.type) {
+ case R_LARCH_TLS_DESC_PC_HI20:
+ case R_LARCH_TLS_DESC_PC_LO12:
+ case R_LARCH_TLS_DESC_PCREL20_S2:
+ write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop
+ break;
+ case R_LARCH_TLS_DESC_LD:
+ write32le(loc, insn(PCALAU12I, R_A0, 0, 0)); // pcalau12i $a0, %ie_pc_hi20
+ relocateNoSym(loc, R_LARCH_TLS_IE_PC_HI20, val);
+ break;
+ case R_LARCH_TLS_DESC_CALL:
+ write32le(loc, insn(ctx.arg.is64 ? LD_D : LD_W, R_A0, R_A0,
+ 0)); // ld.[wd] $a0, $a0, %ie_pc_lo12
+ relocateNoSym(loc, R_LARCH_TLS_IE_PC_LO12, val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLSDESC to IE");
+ }
+}
+
+// Convert TLSDESC GD/LD to LE.
+// The code sequence obtained in the normal or medium code model is as follows:
+// * lu12i.w $a0, %le_hi20(sym_le) # le_hi20 != 0
+// * ori $a0 $a0, %le_lo12(sym_le)
+// See the comment in tlsdescToIe for detailed information.
+void LoongArch::tlsdescToLe(uint8_t *loc, const Relocation &rel,
+ uint64_t val) const {
+ assert(isInt<32>(val) &&
+ "val exceeds the range of medium code model in tlsdescToLe");
+
+ bool isUInt12 = isUInt<12>(val);
+ switch (rel.type) {
+ case R_LARCH_TLS_DESC_PC_HI20:
+ case R_LARCH_TLS_DESC_PC_LO12:
+ case R_LARCH_TLS_DESC_PCREL20_S2:
+ write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop
+ break;
+ case R_LARCH_TLS_DESC_LD:
+ if (isUInt12)
+ write32le(loc, insn(ANDI, R_ZERO, R_ZERO, 0)); // nop
+ else
+ write32le(loc, insn(LU12I_W, R_A0, extractBits(val, 31, 12),
+ 0)); // lu12i.w $a0, %le_hi20
+ break;
+ case R_LARCH_TLS_DESC_CALL:
+ if (isUInt12)
+ write32le(loc, insn(ORI, R_A0, R_ZERO, val)); // ori $a0, $r0, %le_lo12
+ else
+ write32le(loc,
+ insn(ORI, R_A0, R_A0, lo12(val))); // ori $a0, $a0, %le_lo12
----------------
MQ-mengqing wrote:
You're right. Keep the current codes is reasonable.
https://github.com/llvm/llvm-project/pull/123715
More information about the llvm-commits
mailing list