[lld] [llvm] [ELF] Implement R_RISCV_TLSDESC for RISC-V (PR #79099)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 23 12:36:21 PST 2024
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/79099
>From cdf380485d8bfe505f75880b4c800225c2b5d0d8 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Tue, 19 Sep 2023 20:53:54 +0000
Subject: [PATCH 1/2] [RISCV] Support Global Dynamic TLSDESC in the RISC-V
backend
This patch adds basic TLSDESC support for the global dynamic case in the
RISC-V backend by adding new relocation types for TLSDESC, as prescribed
in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373.
We also add a new pseudo instruction to simplify code generation.
Possible improvements for the local dynamic case will be addressed in separate
patches.
The current implementation is only enabled when passing the
-riscv-enable-tlsdesc flag.
---
.../llvm/BinaryFormat/ELFRelocs/RISCV.def | 5 +
llvm/include/llvm/CodeGen/CommandFlags.h | 3 +
llvm/include/llvm/Target/TargetMachine.h | 3 +
llvm/include/llvm/Target/TargetOptions.h | 17 +--
llvm/include/llvm/TargetParser/Triple.h | 7 ++
llvm/lib/CodeGen/CommandFlags.cpp | 8 ++
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 63 +++++++++--
.../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 10 ++
.../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 6 +-
.../MCTargetDesc/RISCVELFObjectWriter.cpp | 15 +++
.../RISCV/MCTargetDesc/RISCVFixupKinds.h | 6 ++
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 40 +++++++
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 18 ++++
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.h | 4 +
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 12 +++
.../Target/RISCV/RISCVExpandPseudoInsts.cpp | 51 +++++++++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 20 +++-
llvm/lib/Target/RISCV/RISCVISelLowering.h | 1 +
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 6 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 29 +++++
llvm/lib/Target/TargetMachine.cpp | 1 +
llvm/test/CodeGen/RISCV/tls-models.ll | 102 ++++++++++++++++++
llvm/test/MC/RISCV/relocations.s | 21 ++++
llvm/test/MC/RISCV/tlsdesc.s | 44 ++++++++
24 files changed, 473 insertions(+), 19 deletions(-)
create mode 100644 llvm/test/MC/RISCV/tlsdesc.s
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
index b478799c91fb2f7..d4be34e3b37e5eb 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
@@ -15,6 +15,7 @@ ELF_RELOC(R_RISCV_TLS_DTPREL32, 8)
ELF_RELOC(R_RISCV_TLS_DTPREL64, 9)
ELF_RELOC(R_RISCV_TLS_TPREL32, 10)
ELF_RELOC(R_RISCV_TLS_TPREL64, 11)
+ELF_RELOC(R_RISCV_TLSDESC, 12)
ELF_RELOC(R_RISCV_BRANCH, 16)
ELF_RELOC(R_RISCV_JAL, 17)
ELF_RELOC(R_RISCV_CALL, 18)
@@ -56,3 +57,7 @@ ELF_RELOC(R_RISCV_IRELATIVE, 58)
ELF_RELOC(R_RISCV_PLT32, 59)
ELF_RELOC(R_RISCV_SET_ULEB128, 60)
ELF_RELOC(R_RISCV_SUB_ULEB128, 61)
+ELF_RELOC(R_RISCV_TLSDESC_HI20, 62)
+ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 63)
+ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 64)
+ELF_RELOC(R_RISCV_TLSDESC_CALL, 65)
diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h
index 6407dde5bcd6c78..bf166a63edb0713 100644
--- a/llvm/include/llvm/CodeGen/CommandFlags.h
+++ b/llvm/include/llvm/CodeGen/CommandFlags.h
@@ -117,6 +117,9 @@ unsigned getTLSSize();
bool getEmulatedTLS();
std::optional<bool> getExplicitEmulatedTLS();
+bool getEnableTLSDESC();
+std::optional<bool> getExplicitEnableTLSDESC();
+
bool getUniqueSectionNames();
bool getUniqueBasicBlockSectionNames();
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 1fe47dec70b1630..a522a12299bb029 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -248,6 +248,9 @@ class TargetMachine {
/// Returns true if this target uses emulated TLS.
bool useEmulatedTLS() const;
+ /// Returns true if this target uses TLS Descriptors.
+ bool useTLSDESC() const;
+
/// Returns the TLS model which should be used for the given global variable.
TLSModel::Model getTLSModel(const GlobalValue *GV) const;
diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index 4df897c047a38ac..d02d1699813c94c 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -145,13 +145,13 @@ namespace llvm {
IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
- EmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false),
- EnableMachineOutliner(false), EnableMachineFunctionSplitter(false),
- SupportsDefaultOutlining(false), EmitAddrsig(false),
- EmitCallSiteInfo(false), SupportsDebugEntryValues(false),
- EnableDebugEntryValues(false), ValueTrackingVariableLocations(false),
- ForceDwarfFrameSection(false), XRayFunctionIndex(true),
- DebugStrictDwarf(false), Hotpatch(false),
+ EmulatedTLS(false), EnableTLSDESC(false), EnableIPRA(false),
+ EmitStackSizeSection(false), EnableMachineOutliner(false),
+ EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
+ EmitAddrsig(false), EmitCallSiteInfo(false),
+ SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
+ ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
+ XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false),
PPCGenScalarMASSEntries(false), JMCInstrument(false),
EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false),
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
@@ -295,6 +295,9 @@ namespace llvm {
/// function in the runtime library..
unsigned EmulatedTLS : 1;
+ /// EnableTLSDESC - This flag enables TLS Descriptors.
+ unsigned EnableTLSDESC : 1;
+
/// This flag enables InterProcedural Register Allocation (IPRA).
unsigned EnableIPRA : 1;
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 1f8c7a060e249d6..870dc75b1c1f80f 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -1033,6 +1033,13 @@ class Triple {
isWindowsCygwinEnvironment() || isOHOSFamily();
}
+ /// Tests whether the target uses TLS Descriptor by default.
+ bool hasDefaultTLSDESC() const {
+ // TODO: Improve check for other platforms, like Android, and RISC-V
+ // Note: This is currently only used on RISC-V.
+ return isOSBinFormatELF() && isAArch64();
+ }
+
/// Tests whether the target uses -data-sections as default.
bool hasDefaultDataSections() const {
return isOSBinFormatXCOFF() || isWasm();
diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp
index c6d7827f36dfd63..51406fb287e6653 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -93,6 +93,7 @@ CGOPT(bool, XCOFFTracebackTable)
CGOPT(std::string, BBSections)
CGOPT(unsigned, TLSSize)
CGOPT_EXP(bool, EmulatedTLS)
+CGOPT_EXP(bool, EnableTLSDESC)
CGOPT(bool, UniqueSectionNames)
CGOPT(bool, UniqueBasicBlockSectionNames)
CGOPT(EABI, EABIVersion)
@@ -404,6 +405,11 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
"emulated-tls", cl::desc("Use emulated TLS model"), cl::init(false));
CGBINDOPT(EmulatedTLS);
+ static cl::opt<bool> EnableTLSDESC(
+ "enable-tlsdesc", cl::desc("Enable the use of TLS Descriptors"),
+ cl::init(false));
+ CGBINDOPT(EnableTLSDESC);
+
static cl::opt<bool> UniqueSectionNames(
"unique-section-names", cl::desc("Give unique names to every section"),
cl::init(true));
@@ -568,6 +574,8 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
Options.TLSSize = getTLSSize();
Options.EmulatedTLS =
getExplicitEmulatedTLS().value_or(TheTriple.hasDefaultEmulatedTLS());
+ Options.EnableTLSDESC =
+ getExplicitEnableTLSDESC().value_or(TheTriple.hasDefaultTLSDESC());
Options.ExceptionModel = getExceptionModel();
Options.EmitStackSizeSection = getEnableStackSizeSection();
Options.EnableMachineFunctionSplitter = getEnableMachineFunctionSplitter();
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 7d42481db57fa90..f6e8386aff45100 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -169,6 +169,12 @@ class RISCVAsmParser : public MCTargetAsmParser {
// 'add' is an overloaded mnemonic.
bool checkPseudoAddTPRel(MCInst &Inst, OperandVector &Operands);
+ // Checks that a PseudoTLSDESCCall is using x5/t0 in its output operand.
+ // Enforcing this using a restricted register class for the output
+ // operand of PseudoTLSDESCCall results in a poor diagnostic due to the fact
+ // 'jalr' is an overloaded mnemonic.
+ bool checkPseudoTLSDESCCall(MCInst &Inst, OperandVector &Operands);
+
// Check instruction constraints.
bool validateInstruction(MCInst &Inst, OperandVector &Operands);
@@ -549,6 +555,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
VK == RISCVMCExpr::VK_RISCV_TPREL_ADD;
}
+ bool isTLSDESCCallSymbol() const {
+ int64_t Imm;
+ RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
+ // Must be of 'immediate' type but not a constant.
+ if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
+ return false;
+ return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_CALL;
+ }
+
bool isCSRSystemRegister() const { return isSystemRegister(); }
bool isVTypeImm(unsigned N) const {
@@ -601,7 +617,10 @@ struct RISCVOperand final : public MCParsedAsmOperand {
if (!isImm())
return false;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- if (VK == RISCVMCExpr::VK_RISCV_LO || VK == RISCVMCExpr::VK_RISCV_PCREL_LO)
+ if (VK == RISCVMCExpr::VK_RISCV_LO ||
+ VK == RISCVMCExpr::VK_RISCV_PCREL_LO ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO)
return true;
// Given only Imm, ensuring that the actually specified constant is either
// a signed or unsigned 64-bit number is unfortunately impossible.
@@ -854,7 +873,9 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return IsValid && ((IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None) ||
VK == RISCVMCExpr::VK_RISCV_LO ||
VK == RISCVMCExpr::VK_RISCV_PCREL_LO ||
- VK == RISCVMCExpr::VK_RISCV_TPREL_LO);
+ VK == RISCVMCExpr::VK_RISCV_TPREL_LO ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO);
}
bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); }
@@ -911,14 +932,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
- VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI);
- } else {
- return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None ||
- VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
- VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
- VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
- VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI);
+ VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI);
}
+
+ return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None ||
+ VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
+ VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
+ VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
+ VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI ||
+ VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI);
}
bool isSImm21Lsb0JAL() const { return isBareSimmNLsb0<21>(); }
@@ -1556,6 +1579,11 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be a symbol with %tprel_add modifier");
}
+ case Match_InvalidTLSDESCCallSymbol: {
+ SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+ return Error(ErrorLoc,
+ "operand must be a symbol with %tlsdesc_call modifier");
+ }
case Match_InvalidRTZArg: {
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be 'rtz' floating-point rounding mode");
@@ -3324,6 +3352,19 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst,
return false;
}
+bool RISCVAsmParser::checkPseudoTLSDESCCall(MCInst &Inst,
+ OperandVector &Operands) {
+ assert(Inst.getOpcode() == RISCV::PseudoTLSDESCCall && "Invalid instruction");
+ assert(Inst.getOperand(0).isReg() && "Unexpected operand kind");
+ if (Inst.getOperand(0).getReg() != RISCV::X5) {
+ SMLoc ErrorLoc = ((RISCVOperand &)*Operands[3]).getStartLoc();
+ return Error(ErrorLoc, "the output operand must be t0/x5 when using "
+ "%tlsdesc_call modifier");
+ }
+
+ return false;
+}
+
std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultMaskRegOp() const {
return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(),
llvm::SMLoc());
@@ -3559,6 +3600,10 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
if (checkPseudoAddTPRel(Inst, Operands))
return true;
break;
+ case RISCV::PseudoTLSDESCCall:
+ if (checkPseudoTLSDESCCall(Inst, Operands))
+ return true;
+ break;
case RISCV::PseudoSEXT_B:
emitPseudoExtend(Inst, /*SignExtend=*/true, /*Width=*/8, IDLoc, Out);
return false;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 7ce08eabdeb61db..bd49875c9591d01 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -86,6 +86,12 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
{"fixup_riscv_relax", 0, 0, 0},
{"fixup_riscv_align", 0, 0, 0},
+
+ {"fixup_riscv_tlsdesc_hi20", 12, 20,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
+ {"fixup_riscv_tlsdesc_load_lo12", 20, 12, 0},
+ {"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
+ {"fixup_riscv_tlsdesc_call", 0, 0, 0},
};
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
"Not all fixup kinds added to Infos array");
@@ -126,6 +132,7 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
case RISCV::fixup_riscv_got_hi20:
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
+ case RISCV::fixup_riscv_tlsdesc_hi20:
return true;
}
@@ -411,6 +418,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case RISCV::fixup_riscv_got_hi20:
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
+ case RISCV::fixup_riscv_tlsdesc_hi20:
llvm_unreachable("Relocation should be unconditionally forced\n");
case FK_Data_1:
case FK_Data_2:
@@ -421,6 +429,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
case RISCV::fixup_riscv_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_i:
case RISCV::fixup_riscv_tprel_lo12_i:
+ case RISCV::fixup_riscv_tlsdesc_load_lo12:
return Value & 0xfff;
case RISCV::fixup_riscv_12_i:
if (!isInt<12>(Value)) {
@@ -524,6 +533,7 @@ bool RISCVAsmBackend::evaluateTargetFixup(
switch (Fixup.getTargetKind()) {
default:
llvm_unreachable("Unexpected fixup kind!");
+ case RISCV::fixup_riscv_tlsdesc_hi20:
case RISCV::fixup_riscv_pcrel_hi20:
AUIPCFixup = &Fixup;
AUIPCDF = DF;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 433e2e6f80bd68a..d7f7859ce4399bd 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -264,11 +264,15 @@ enum {
MO_TPREL_ADD = 10,
MO_TLS_GOT_HI = 11,
MO_TLS_GD_HI = 12,
+ MO_TLSDESC_HI = 13,
+ MO_TLSDESC_LOAD_LO = 14,
+ MO_TLSDESC_ADD_LO = 15,
+ MO_TLSDESC_CALL = 16,
// Used to differentiate between target-specific "direct" flags and "bitmask"
// flags. A machine operand can only have one "direct" flag, but can have
// multiple "bitmask" flags.
- MO_DIRECT_FLAG_MASK = 15
+ MO_DIRECT_FLAG_MASK = 31
};
} // namespace RISCVII
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
index 76e5b3ed402543b..2343c5fb2535a55 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -77,6 +77,14 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
return ELF::R_RISCV_TLS_GOT_HI20;
case RISCV::fixup_riscv_tls_gd_hi20:
return ELF::R_RISCV_TLS_GD_HI20;
+ case RISCV::fixup_riscv_tlsdesc_hi20:
+ return ELF::R_RISCV_TLSDESC_HI20;
+ case RISCV::fixup_riscv_tlsdesc_load_lo12:
+ return ELF::R_RISCV_TLSDESC_LOAD_LO12;
+ case RISCV::fixup_riscv_tlsdesc_add_lo12:
+ return ELF::R_RISCV_TLSDESC_ADD_LO12;
+ case RISCV::fixup_riscv_tlsdesc_call:
+ return ELF::R_RISCV_TLSDESC_CALL;
case RISCV::fixup_riscv_jal:
return ELF::R_RISCV_JAL;
case RISCV::fixup_riscv_branch:
@@ -96,6 +104,13 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
default:
Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");
return ELF::R_RISCV_NONE;
+ case RISCV::fixup_riscv_tlsdesc_load_lo12:
+ return ELF::R_RISCV_TLSDESC_LOAD_LO12;
+ case RISCV::fixup_riscv_tlsdesc_add_lo12:
+ return ELF::R_RISCV_TLSDESC_ADD_LO12;
+ case RISCV::fixup_riscv_tlsdesc_call:
+ return ELF::R_RISCV_TLSDESC_CALL;
+
case FK_Data_1:
Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
return ELF::R_RISCV_NONE;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index 74bd9398a9ef6b8..821372d3d39a63f 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -71,6 +71,12 @@ enum Fixups {
// Used to generate an R_RISCV_ALIGN relocation, which indicates the linker
// should fixup the alignment after linker relaxation.
fixup_riscv_align,
+ // Fixups indicating a TLS descriptor code sequence, corresponding to auipc,
+ // lw/ld, addi, and jalr, respectively.
+ fixup_riscv_tlsdesc_hi20,
+ fixup_riscv_tlsdesc_load_lo12,
+ fixup_riscv_tlsdesc_add_lo12,
+ fixup_riscv_tlsdesc_call,
// Used as a sentinel, must be the last
fixup_riscv_invalid,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 82fed50bce753a9..5ea386c3c32a3dd 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -57,6 +57,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandTLSDESCCall(const MCInst &MI, SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
void expandAddTPRel(const MCInst &MI, SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -154,6 +158,26 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI,
support::endian::write(CB, Binary, llvm::endianness::little);
}
+void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI,
+ SmallVectorImpl<char> &CB,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ MCOperand SrcSymbol = MI.getOperand(3);
+ assert(SrcSymbol.isExpr() &&
+ "Expected expression as first input to TLSDESCCALL");
+ const RISCVMCExpr *Expr = dyn_cast<RISCVMCExpr>(SrcSymbol.getExpr());
+ MCRegister Link = MI.getOperand(0).getReg();
+ MCRegister Dest = MI.getOperand(1).getReg();
+ MCRegister Imm = MI.getOperand(2).getImm();
+ Fixups.push_back(MCFixup::create(
+ 0, Expr, MCFixupKind(RISCV::fixup_riscv_tlsdesc_call), MI.getLoc()));
+ MCInst Call =
+ MCInstBuilder(RISCV::JALR).addReg(Link).addReg(Dest).addImm(Imm);
+
+ uint32_t Binary = getBinaryCodeForInstr(Call, Fixups, STI);
+ support::endian::write(CB, Binary, llvm::endianness::little);
+}
+
// Expand PseudoAddTPRel to a simple ADD with the correct relocation.
void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
SmallVectorImpl<char> &CB,
@@ -303,6 +327,10 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
expandLongCondBr(MI, CB, Fixups, STI);
MCNumEmitted += 2;
return;
+ case RISCV::PseudoTLSDESCCall:
+ expandTLSDESCCall(MI, CB, Fixups, STI);
+ MCNumEmitted += 1;
+ return;
}
switch (Size) {
@@ -445,6 +473,18 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
FixupKind = RISCV::fixup_riscv_call_plt;
RelaxCandidate = true;
break;
+ case RISCVMCExpr::VK_RISCV_TLSDESC_HI:
+ FixupKind = RISCV::fixup_riscv_tlsdesc_hi20;
+ break;
+ case RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO:
+ FixupKind = RISCV::fixup_riscv_tlsdesc_load_lo12;
+ break;
+ case RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO:
+ FixupKind = RISCV::fixup_riscv_tlsdesc_add_lo12;
+ break;
+ case RISCVMCExpr::VK_RISCV_TLSDESC_CALL:
+ FixupKind = RISCV::fixup_riscv_tlsdesc_call;
+ break;
}
} else if ((Kind == MCExpr::SymbolRef &&
cast<MCSymbolRefExpr>(Expr)->getKind() ==
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
index 64ddae61b1bc159..254a9a4bc0ef0b1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -79,6 +79,7 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const {
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
case RISCV::fixup_riscv_pcrel_hi20:
+ case RISCV::fixup_riscv_tlsdesc_hi20:
if (DFOut)
*DFOut = DF;
return &F;
@@ -119,6 +120,10 @@ RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
.Case("tprel_add", VK_RISCV_TPREL_ADD)
.Case("tls_ie_pcrel_hi", VK_RISCV_TLS_GOT_HI)
.Case("tls_gd_pcrel_hi", VK_RISCV_TLS_GD_HI)
+ .Case("tlsdesc_hi", VK_RISCV_TLSDESC_HI)
+ .Case("tlsdesc_load_lo", VK_RISCV_TLSDESC_LOAD_LO)
+ .Case("tlsdesc_add_lo", VK_RISCV_TLSDESC_ADD_LO)
+ .Case("tlsdesc_call", VK_RISCV_TLSDESC_CALL)
.Default(VK_RISCV_Invalid);
}
@@ -145,6 +150,14 @@ StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
return "tprel_add";
case VK_RISCV_TLS_GOT_HI:
return "tls_ie_pcrel_hi";
+ case VK_RISCV_TLSDESC_HI:
+ return "tlsdesc_hi";
+ case VK_RISCV_TLSDESC_LOAD_LO:
+ return "tlsdesc_load_lo";
+ case VK_RISCV_TLSDESC_ADD_LO:
+ return "tlsdesc_add_lo";
+ case VK_RISCV_TLSDESC_CALL:
+ return "tlsdesc_call";
case VK_RISCV_TLS_GD_HI:
return "tls_gd_pcrel_hi";
case VK_RISCV_CALL:
@@ -193,6 +206,9 @@ void RISCVMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
case VK_RISCV_TPREL_HI:
case VK_RISCV_TLS_GOT_HI:
case VK_RISCV_TLS_GD_HI:
+ case VK_RISCV_TLSDESC_HI:
+ case VK_RISCV_TLSDESC_ADD_LO:
+ case VK_RISCV_TLSDESC_LOAD_LO:
break;
}
@@ -206,6 +222,8 @@ bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI ||
Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD ||
Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI ||
+ Kind == VK_RISCV_TLSDESC_HI || Kind == VK_RISCV_TLSDESC_LOAD_LO ||
+ Kind == VK_RISCV_TLSDESC_ADD_LO || Kind == VK_RISCV_TLSDESC_CALL ||
Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT)
return false;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
index ee83bf0208ef46e..fcc4c5c439645a9 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
@@ -37,6 +37,10 @@ class RISCVMCExpr : public MCTargetExpr {
VK_RISCV_CALL,
VK_RISCV_CALL_PLT,
VK_RISCV_32_PCREL,
+ VK_RISCV_TLSDESC_HI,
+ VK_RISCV_TLSDESC_LOAD_LO,
+ VK_RISCV_TLSDESC_ADD_LO,
+ VK_RISCV_TLSDESC_CALL,
VK_RISCV_Invalid // Must be the last item
};
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index aee6ec05f1f9c5e..b2e9cd87373b0f0 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -780,6 +780,18 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
case RISCVII::MO_TLS_GD_HI:
Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI;
break;
+ case RISCVII::MO_TLSDESC_HI:
+ Kind = RISCVMCExpr::VK_RISCV_TLSDESC_HI;
+ break;
+ case RISCVII::MO_TLSDESC_LOAD_LO:
+ Kind = RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO;
+ break;
+ case RISCVII::MO_TLSDESC_ADD_LO:
+ Kind = RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO;
+ break;
+ case RISCVII::MO_TLSDESC_CALL:
+ Kind = RISCVMCExpr::VK_RISCV_TLSDESC_CALL;
+ break;
}
const MCExpr *ME =
diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
index ed2b1ceb7d6f0dc..0a314fdd41cbe2b 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -423,6 +423,10 @@ class RISCVPreRAExpandPseudo : public MachineFunctionPass {
bool expandLoadTLSGDAddress(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
+ bool expandLoadTLSDescAddress(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI);
+
#ifndef NDEBUG
unsigned getInstSizeInBytes(const MachineFunction &MF) const {
unsigned Size = 0;
@@ -481,6 +485,8 @@ bool RISCVPreRAExpandPseudo::expandMI(MachineBasicBlock &MBB,
return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoLA_TLS_GD:
return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI);
+ case RISCV::PseudoLA_TLSDESC:
+ return expandLoadTLSDescAddress(MBB, MBBI, NextMBBI);
}
return false;
}
@@ -547,6 +553,51 @@ bool RISCVPreRAExpandPseudo::expandLoadTLSGDAddress(
RISCV::ADDI);
}
+bool RISCVPreRAExpandPseudo::expandLoadTLSDescAddress(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ MachineBasicBlock::iterator &NextMBBI) {
+ MachineFunction *MF = MBB.getParent();
+ MachineInstr &MI = *MBBI;
+ DebugLoc DL = MI.getDebugLoc();
+
+ const auto &STI = MF->getSubtarget<RISCVSubtarget>();
+ unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW;
+
+ Register FinalReg = MI.getOperand(0).getReg();
+ Register DestReg =
+ MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
+ Register ScratchReg =
+ MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
+
+ MachineOperand &Symbol = MI.getOperand(1);
+ Symbol.setTargetFlags(RISCVII::MO_TLSDESC_HI);
+ MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol("tlsdesc_hi");
+
+ MachineInstr *MIAUIPC =
+ BuildMI(MBB, MBBI, DL, TII->get(RISCV::AUIPC), ScratchReg).add(Symbol);
+ MIAUIPC->setPreInstrSymbol(*MF, AUIPCSymbol);
+
+ BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg)
+ .addReg(ScratchReg)
+ .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_LOAD_LO);
+
+ BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), RISCV::X10)
+ .addReg(ScratchReg)
+ .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_ADD_LO);
+
+ BuildMI(MBB, MBBI, DL, TII->get(RISCV::PseudoTLSDESCCall), RISCV::X5)
+ .addReg(DestReg)
+ .addImm(0)
+ .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_CALL);
+
+ BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg)
+ .addReg(RISCV::X10)
+ .addReg(RISCV::X4);
+
+ MI.eraseFromParent();
+ return true;
+}
+
} // end of anonymous namespace
INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index e39888637062c6e..47c6cd6e5487b80 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6982,6 +6982,23 @@ SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
return LowerCallTo(CLI).first;
}
+SDValue RISCVTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
+ SelectionDAG &DAG) const {
+ SDLoc DL(N);
+ EVT Ty = getPointerTy(DAG.getDataLayout());
+ const GlobalValue *GV = N->getGlobal();
+
+ // Use a PC-relative addressing mode to access the global dynamic GOT address.
+ // This generates the pattern (PseudoLA_TLSDESC sym), which expands to
+ //
+ // auipc tX, %tlsdesc_hi(symbol) // R_RISCV_TLSDESC_HI20(symbol)
+ // lw tY, tX, %tlsdesc_lo_load(label) // R_RISCV_TLSDESC_LOAD_LO12_I(label)
+ // addi a0, tX, %tlsdesc_lo_add(label) // R_RISCV_TLSDESC_ADD_LO12_I(label)
+ // jalr t0, tY // R_RISCV_TLSDESC_CALL(label)
+ SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
+ return SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLSDESC, DL, Ty, Addr), 0);
+}
+
SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
@@ -7006,7 +7023,8 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
break;
case TLSModel::LocalDynamic:
case TLSModel::GeneralDynamic:
- Addr = getDynamicTLSAddr(N, DAG);
+ Addr = DAG.getTarget().useTLSDESC() ? getTLSDescAddr(N, DAG)
+ : getDynamicTLSAddr(N, DAG);
break;
}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index a55a6046166719c..30b9ad7e6f6f326 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -855,6 +855,7 @@ class RISCVTargetLowering : public TargetLowering {
SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
bool UseGOT) const;
SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const;
+ SDValue getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 7c21f6358494285..592962cebe89731 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2379,7 +2379,11 @@ RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
{MO_TPREL_HI, "riscv-tprel-hi"},
{MO_TPREL_ADD, "riscv-tprel-add"},
{MO_TLS_GOT_HI, "riscv-tls-got-hi"},
- {MO_TLS_GD_HI, "riscv-tls-gd-hi"}};
+ {MO_TLS_GD_HI, "riscv-tls-gd-hi"},
+ {MO_TLSDESC_HI, "riscv-tlsdesc-hi"},
+ {MO_TLSDESC_LOAD_LO, "riscv-tlsdesc-load-lo"},
+ {MO_TLSDESC_ADD_LO, "riscv-tlsdesc-add-lo"},
+ {MO_TLSDESC_CALL, "riscv-tlsdesc-call"}};
return ArrayRef(TargetFlags);
}
bool RISCVInstrInfo::isFunctionSafeToOutlineFrom(
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 792e0bbdf5816cf..114329c2c7c5f38 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1742,6 +1742,35 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0,
def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
"la.tls.gd", "$dst, $src">;
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 32, isCodeGenOnly = 0 in
+def PseudoLA_TLSDESC : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
+ "la.tlsdesc", "$dst, $src">;
+
+def TLSDESCCallSymbol : AsmOperandClass {
+ let Name = "TLSDESCCallSymbol";
+ let RenderMethod = "addImmOperands";
+ let DiagnosticType = "InvalidTLSDESCCallSymbol";
+ let ParserMethod = "parseOperandWithModifier";
+}
+
+// A bare symbol with the %tlsdesc_call variant.
+def tlsdesc_call_symbol : Operand<XLenVT> {
+ let ParserMatchClass = TLSDESCCallSymbol;
+}
+// This is a special case of the JALR instruction used to facilitate the use of a
+// fourth operand to emit a relocation on a symbol relating to this instruction.
+// The relocation does not affect any bits of the instruction itself but is used
+// as a hint to the linker.
+let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, Size = 8, hasSideEffects = 0,
+ mayStore = 0, mayLoad = 0 in
+def PseudoTLSDESCCall : Pseudo<(outs GPR:$rd),
+ (ins GPR:$rs1, simm12:$imm12, tlsdesc_call_symbol:$src), [],
+ "jalr", "$rd, ${imm12}(${rs1}), $src">,
+ Sched<[WriteJalr, ReadJalr]> {
+ let Defs = [X10];
+ let Uses = [X10];
+}
+
/// Sign/Zero Extends
diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp
index abd0fdf2390c044..0839fb22d35a8fe 100644
--- a/llvm/lib/Target/TargetMachine.cpp
+++ b/llvm/lib/Target/TargetMachine.cpp
@@ -213,6 +213,7 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M,
}
bool TargetMachine::useEmulatedTLS() const { return Options.EmulatedTLS; }
+bool TargetMachine::useTLSDESC() const { return Options.EnableTLSDESC; }
TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const {
bool IsPIE = GV->getParent()->getPIELevel() != PIELevel::Default;
diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll
index c2ed44073baac16..b99896e35019117 100644
--- a/llvm/test/CodeGen/RISCV/tls-models.ll
+++ b/llvm/test/CodeGen/RISCV/tls-models.ll
@@ -1,10 +1,16 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s \
; RUN: | FileCheck -check-prefix=RV32-PIC %s
+; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s -enable-tlsdesc \
+; RUN: | FileCheck -check-prefix=RV32-PIC-TLSDESC %s
; RUN: llc -mtriple=riscv64 -relocation-model=pic < %s \
; RUN: | FileCheck -check-prefix=RV64-PIC %s
+; RUN: llc -mtriple=riscv64 -relocation-model=pic -enable-tlsdesc < %s \
+; RUN: | FileCheck -check-prefix=RV64-PIC-TLSDESC %s
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32-NOPIC %s
+; RUN: llc -mtriple=riscv32 < %s -enable-tlsdesc | FileCheck -check-prefix=RV32-NOPIC-TLSDESC %s
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64-NOPIC %s
+; RUN: llc -mtriple=riscv64 < %s -enable-tlsdesc | FileCheck -check-prefix=RV64-NOPIC-TLSDESC %s
; Check that TLS symbols are lowered correctly based on the specified
; model. Make sure they're external to avoid them all being optimised to Local
@@ -58,6 +64,42 @@ define ptr @f1() nounwind {
; RV64-NOPIC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
; RV64-NOPIC-NEXT: add a0, a0, tp
; RV64-NOPIC-NEXT: ret
+;
+; RV32-PIC-TLSDESC-LABEL: f1:
+; RV32-PIC-TLSDESC: # %bb.0: # %entry
+; RV32-PIC-TLSDESC-NEXT: .Ltlsdesc_hi0:
+; RV32-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(unspecified)
+; RV32-PIC-TLSDESC-NEXT: lw a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+; RV32-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp
+; RV32-PIC-TLSDESC-NEXT: ret
+;
+; RV64-PIC-TLSDESC-LABEL: f1:
+; RV64-PIC-TLSDESC: # %bb.0: # %entry
+; RV64-PIC-TLSDESC-NEXT: .Ltlsdesc_hi0:
+; RV64-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(unspecified)
+; RV64-PIC-TLSDESC-NEXT: ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+; RV64-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp
+; RV64-PIC-TLSDESC-NEXT: ret
+;
+; RV32-NOPIC-TLSDESC-LABEL: f1:
+; RV32-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV32-NOPIC-TLSDESC-NEXT: .Lpcrel_hi0:
+; RV32-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(unspecified)
+; RV32-NOPIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp
+; RV32-NOPIC-TLSDESC-NEXT: ret
+;
+; RV64-NOPIC-TLSDESC-LABEL: f1:
+; RV64-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV64-NOPIC-TLSDESC-NEXT: .Lpcrel_hi0:
+; RV64-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(unspecified)
+; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp
+; RV64-NOPIC-TLSDESC-NEXT: ret
entry:
ret ptr @unspecified
}
@@ -144,6 +186,38 @@ define ptr @f3() nounwind {
; RV64-NOPIC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0)
; RV64-NOPIC-NEXT: add a0, a0, tp
; RV64-NOPIC-NEXT: ret
+;
+; RV32-PIC-TLSDESC-LABEL: f3:
+; RV32-PIC-TLSDESC: # %bb.0: # %entry
+; RV32-PIC-TLSDESC-NEXT: .Lpcrel_hi0:
+; RV32-PIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie)
+; RV32-PIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp
+; RV32-PIC-TLSDESC-NEXT: ret
+;
+; RV64-PIC-TLSDESC-LABEL: f3:
+; RV64-PIC-TLSDESC: # %bb.0: # %entry
+; RV64-PIC-TLSDESC-NEXT: .Lpcrel_hi0:
+; RV64-PIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie)
+; RV64-PIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0)
+; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp
+; RV64-PIC-TLSDESC-NEXT: ret
+;
+; RV32-NOPIC-TLSDESC-LABEL: f3:
+; RV32-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV32-NOPIC-TLSDESC-NEXT: .Lpcrel_hi2:
+; RV32-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie)
+; RV32-NOPIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi2)(a0)
+; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp
+; RV32-NOPIC-TLSDESC-NEXT: ret
+;
+; RV64-NOPIC-TLSDESC-LABEL: f3:
+; RV64-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV64-NOPIC-TLSDESC-NEXT: .Lpcrel_hi2:
+; RV64-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie)
+; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0)
+; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp
+; RV64-NOPIC-TLSDESC-NEXT: ret
entry:
ret ptr @ie
}
@@ -179,6 +253,34 @@ define ptr @f4() nounwind {
; RV64-NOPIC-NEXT: add a0, a0, tp, %tprel_add(le)
; RV64-NOPIC-NEXT: addi a0, a0, %tprel_lo(le)
; RV64-NOPIC-NEXT: ret
+;
+; RV32-PIC-TLSDESC-LABEL: f4:
+; RV32-PIC-TLSDESC: # %bb.0: # %entry
+; RV32-PIC-TLSDESC-NEXT: lui a0, %tprel_hi(le)
+; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le)
+; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le)
+; RV32-PIC-TLSDESC-NEXT: ret
+;
+; RV64-PIC-TLSDESC-LABEL: f4:
+; RV64-PIC-TLSDESC: # %bb.0: # %entry
+; RV64-PIC-TLSDESC-NEXT: lui a0, %tprel_hi(le)
+; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le)
+; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le)
+; RV64-PIC-TLSDESC-NEXT: ret
+;
+; RV32-NOPIC-TLSDESC-LABEL: f4:
+; RV32-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV32-NOPIC-TLSDESC-NEXT: lui a0, %tprel_hi(le)
+; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le)
+; RV32-NOPIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le)
+; RV32-NOPIC-TLSDESC-NEXT: ret
+;
+; RV64-NOPIC-TLSDESC-LABEL: f4:
+; RV64-NOPIC-TLSDESC: # %bb.0: # %entry
+; RV64-NOPIC-TLSDESC-NEXT: lui a0, %tprel_hi(le)
+; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le)
+; RV64-NOPIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le)
+; RV64-NOPIC-TLSDESC-NEXT: ret
entry:
ret ptr @le
}
diff --git a/llvm/test/MC/RISCV/relocations.s b/llvm/test/MC/RISCV/relocations.s
index 262b3e44c6f007b..d9d941697704c2b 100644
--- a/llvm/test/MC/RISCV/relocations.s
+++ b/llvm/test/MC/RISCV/relocations.s
@@ -176,3 +176,24 @@ bgeu a0, a1, foo
# RELOC: R_RISCV_JAL
# INSTR: bgeu a0, a1, foo
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch
+
+.L5:
+auipc a0, %tlsdesc_hi(a_symbol)
+# RELOC: R_RISCV_TLSDESC_HI20
+# INST: auipc a0, 0x0
+# FIXUP: fixup A - offset: 0, value: %tlsdesc_hi(a_symbol), kind: fixup_riscv_tlsdesc_hi20
+
+lw a1, %tlsdesc_load_lo(.L5)(a0)
+# RELOC: R_RISCV_TLSDESC_LOAD_LO12
+# INST: lw a1, 0x0(a0)
+# FIXUP: fixup A - offset: 0, value: %tlsdesc_load_lo(.L5), kind: fixup_riscv_tlsdesc_load_lo12
+
+addi a0, a0, %tlsdesc_add_lo(.L5)
+# RELOC: R_RISCV_TLSDESC_ADD_LO12
+# INST: addi a0, a0, 0x0
+# FIXUP: fixup A - offset: 0, value: %tlsdesc_add_lo(.L5), kind: fixup_riscv_tlsdesc_add_lo12
+
+jalr t0, 0(a1), %tlsdesc_call(.L5)
+# RELOC: R_RISCV_TLSDESC_CALL
+# INST: jalr t0, 0x0(a1)
+# FIXUP: fixup A - offset: 0, value: %tlsdesc_call(.L5), kind: fixup_riscv_tlsdesc_call
diff --git a/llvm/test/MC/RISCV/tlsdesc.s b/llvm/test/MC/RISCV/tlsdesc.s
new file mode 100644
index 000000000000000..f455e266ab1557d
--- /dev/null
+++ b/llvm/test/MC/RISCV/tlsdesc.s
@@ -0,0 +1,44 @@
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s --defsym RV32=1 | llvm-objdump -d -M no-aliases - | FileCheck %s --check-prefixes=INST,RV32
+# RUN: llvm-mc -filetype=obj -triple riscv64 < %s | llvm-objdump -d -M no-aliases - | FileCheck %s --check-prefixes=INST,RV64
+
+# RUN: not llvm-mc -triple riscv32 < %s --defsym RV32=1 --defsym ERR=1 2>&1 | FileCheck %s --check-prefixes=ERR
+# RUN: not llvm-mc -triple riscv64 < %s --defsym ERR=1 2>&1 | FileCheck %s --check-prefixes=ERR
+
+start: # @start
+# %bb.0: # %entry
+.Ltlsdesc_hi0:
+ auipc a0, %tlsdesc_hi(a-4)
+ # INST: auipc a0, 0x0
+ auipc a0, %tlsdesc_hi(unspecified)
+ # INST: auipc a0, 0x0
+.ifdef RV32
+ lw a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+ # RV32: lw a1, 0x0(a0)
+.else
+ ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+ #RV64: ld a1, 0x0(a0)
+.endif
+ addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+ # INST: addi a0, a0, 0x0
+ jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+ # INST: jalr t0, 0x0(a1)
+ add a0, a0, tp
+ # INST: add a0, a0, tp
+ ret
+
+## Check invalid usage
+.ifdef ERR
+ auipc x1, %tlsdesc_call(foo) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range
+ auipc x1, %tlsdesc_call(1234) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range
+ auipc a0, %tlsdesc_hi(a+b) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range
+
+ lw a0, t0, %tlsdesc_load_lo(a_symbol) # ERR: :[[#@LINE]]:15: error: invalid operand for instruction
+ lw a0, t0, %tlsdesc_load_lo(a_symbol)(a4) # ERR: :[[#@LINE]]:15: error: invalid operand for instruction
+
+ addi a0, t0, %tlsdesc_add_lo(a_symbol)(a4) # ERR: :[[#@LINE]]:41: error: invalid operand for instruction
+ addi a0, %tlsdesc_add_lo(a_symbol) # ERR: :[[#@LINE]]:11: error: invalid operand for instruction
+ addi x1, %tlsdesc_load_lo(a_symbol)(a0) # ERR: :[[#@LINE]]:11: error: invalid operand for instruction
+
+ jalr x5, 0(a1), %tlsdesc_hi(a_symbol) # ERR: :[[#@LINE]]:18: error: operand must be a symbol with %tlsdesc_call modifier
+ jalr x1, 0(a1), %tlsdesc_call(a_symbol) # ERR: :[[#@LINE]]:13: error: the output operand must be t0/x5 when using %tlsdesc_call modifier
+.endif
>From 803d1406c635ecf63e17d01d351c458eb1e870b7 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Mon, 22 Jan 2024 16:33:34 -0800
Subject: [PATCH 2/2] [ELF] Implement R_RISCV_TLSDESC for RISC-V
Support
R_RISCV_TLSDESC_HI20/R_RISCV_TLSDESC_LOAD_LO12_I/R_RISCV_TLSDESC_ADD_LO12_I/R_RISCV_TLSDESC_CALL.
LOAD_LO12_I/ADD_LO12_I/CALL relocations reference a label at the HI20
location, which requires special handling. We save the value of HI20 to
be reused.
For -no-pie/-pie links, TLSDESC to initial-exec or local-exec
optimizations are eligible. Implement the relevant hooks
(R_RELAX_TLS_GD_TO_LE, R_RELAX_TLS_GD_TO_IE). AUIPC/L[DW] for
initial-exec uses GOT offsets, which may be adjusted in the presence of
linker relaxation.
```
// TLSDESC to LE/IE optimization
.Ltlsdesc_hi2:
auipc a4, %tlsdesc_hi(c) # if R_RISCV_RELAX: remove; otherwise, NOP
load a5, %tlsdesc_load_lo(.Ltlsdesc_hi2)(a4) # if R_RISCV_RELAX: remove; otherwise, NOP
addi a0, a4, %tlsdesc_add_lo(.Ltlsdesc_hi2)
jalr t0, 0(a5), %tlsdesc_call(.Ltlsdesc_hi2)
add a0, a0, tp
```
* `riscv64-tlsdesc.s` is inspired by `i386-tlsdesc-gd.s` (https://reviews.llvm.org/D112582).
* `riscv64-tlsdesc-relax.s` tests linker relaxation.
DO NOT SUBMIT: rebase after #66915 lands
---
lld/ELF/Arch/RISCV.cpp | 158 +++++++++++++++++----
lld/ELF/Relocations.cpp | 25 ++--
lld/test/ELF/riscv-tlsdesc-gd-mixed.s | 26 ++++
lld/test/ELF/riscv-tlsdesc-relax.s | 125 +++++++++++++++++
lld/test/ELF/riscv-tlsdesc.s | 192 ++++++++++++++++++++++++++
5 files changed, 492 insertions(+), 34 deletions(-)
create mode 100644 lld/test/ELF/riscv-tlsdesc-gd-mixed.s
create mode 100644 lld/test/ELF/riscv-tlsdesc-relax.s
create mode 100644 lld/test/ELF/riscv-tlsdesc.s
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index d7d3d3e47814971..67d7e2562e9b178 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -61,6 +61,7 @@ enum Op {
AUIPC = 0x17,
JALR = 0x67,
LD = 0x3003,
+ LUI = 0x37,
LW = 0x2003,
SRLI = 0x5013,
SUB = 0x40000033,
@@ -73,6 +74,7 @@ enum Reg {
X_T0 = 5,
X_T1 = 6,
X_T2 = 7,
+ X_A0 = 10,
X_T3 = 28,
};
@@ -102,6 +104,26 @@ static uint32_t setLO12_S(uint32_t insn, uint32_t imm) {
(extractBits(imm, 4, 0) << 7);
}
+namespace {
+struct SymbolAnchor {
+ uint64_t offset;
+ Defined *d;
+ bool end; // true for the anchor of st_value+st_size
+};
+} // namespace
+
+struct elf::RISCVRelaxAux {
+ // This records symbol start and end offsets which will be adjusted according
+ // to the nearest relocDeltas element.
+ SmallVector<SymbolAnchor, 0> anchors;
+ // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
+ // 0).
+ std::unique_ptr<uint32_t[]> relocDeltas;
+ // For relocations[i], the actual type is relocTypes[i].
+ std::unique_ptr<RelType[]> relocTypes;
+ SmallVector<uint32_t, 0> writes;
+};
+
RISCV::RISCV() {
copyRel = R_RISCV_COPY;
pltRel = R_RISCV_JUMP_SLOT;
@@ -119,6 +141,7 @@ RISCV::RISCV() {
tlsGotRel = R_RISCV_TLS_TPREL32;
}
gotRel = symbolicRel;
+ tlsDescRel = R_RISCV_TLSDESC;
// .got[0] = _DYNAMIC
gotHeaderEntriesNum = 1;
@@ -187,6 +210,8 @@ int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_RISCV_JUMP_SLOT:
// These relocations are defined as not having an implicit addend.
return 0;
+ case R_RISCV_TLSDESC:
+ return config->is64 ? read64le(buf + 8) : read32le(buf + 4);
}
}
@@ -295,6 +320,12 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
return R_RISCV_PC_INDIRECT;
+ case R_RISCV_TLSDESC_HI20:
+ case R_RISCV_TLSDESC_LOAD_LO12:
+ case R_RISCV_TLSDESC_ADD_LO12:
+ return R_TLSDESC_PC;
+ case R_RISCV_TLSDESC_CALL:
+ return R_TLSDESC_CALL;
case R_RISCV_TLS_GD_HI20:
return R_TLSGD_PC;
case R_RISCV_TLS_GOT_HI20:
@@ -419,6 +450,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
case R_RISCV_GOT_HI20:
case R_RISCV_PCREL_HI20:
+ case R_RISCV_TLSDESC_HI20:
case R_RISCV_TLS_GD_HI20:
case R_RISCV_TLS_GOT_HI20:
case R_RISCV_TPREL_HI20:
@@ -430,6 +462,8 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
}
case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_TLSDESC_LOAD_LO12:
+ case R_RISCV_TLSDESC_ADD_LO12:
case R_RISCV_TPREL_LO12_I:
case R_RISCV_LO12_I: {
uint64_t hi = (val + 0x800) >> 12;
@@ -513,29 +547,113 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
break;
case R_RISCV_RELAX:
- return; // Ignored (for now)
-
+ return;
+ case R_RISCV_TLSDESC:
+ // The addend is stored in the second word.
+ if (config->is64)
+ write64le(loc + 8, val);
+ else
+ write32le(loc + 4, val);
+ break;
default:
llvm_unreachable("unknown relocation");
}
}
+static void tlsdescToIe(uint8_t *loc, const Relocation &rel, uint64_t val) {
+ switch (rel.type) {
+ case R_RISCV_TLSDESC_HI20:
+ case R_RISCV_TLSDESC_LOAD_LO12:
+ write32le(loc, 0x00000013); // nop
+ return;
+ case R_RISCV_TLSDESC_ADD_LO12:
+ write32le(loc, utype(AUIPC, X_A0, hi20(val))); // auipc a0,<hi20>
+ return;
+ case R_RISCV_TLSDESC_CALL:
+ if (config->is64)
+ write32le(loc, itype(LD, X_A0, X_A0, lo12(val))); // ld a0,<lo12>(a0)
+ else
+ write32le(loc, itype(LW, X_A0, X_A0, lo12(val))); // lw a0,<lo12>(a0)
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLSDESC to IE relaxation");
+ }
+}
+
+static void tlsdescToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
+ switch (rel.type) {
+ case R_RISCV_TLSDESC_HI20:
+ case R_RISCV_TLSDESC_LOAD_LO12:
+ write32le(loc, 0x00000013); // nop
+ return;
+ case R_RISCV_TLSDESC_ADD_LO12:
+ write32le(loc, utype(LUI, X_A0, hi20(val))); // lui a0,<hi20>
+ return;
+ case R_RISCV_TLSDESC_CALL:
+ if (isInt<12>(val))
+ write32le(loc, itype(ADDI, X_A0, 0, val)); // addi a0,zero,<lo12>
+ else
+ write32le(loc, itype(ADDI, X_A0, X_A0, lo12(val))); // addi a0,a0,<lo12>
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLSDESC to LE relaxation");
+ }
+}
+
void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
secAddr += ehIn->getParent()->outSecOff;
- for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
- const Relocation &rel = sec.relocs()[i];
+ uint64_t tlsdescVal = 0;
+ bool isToIe = true;
+ const ArrayRef<Relocation> relocs = sec.relocs();
+ for (size_t i = 0, size = relocs.size(); i != size; ++i) {
+ const Relocation &rel = relocs[i];
uint8_t *loc = buf + rel.offset;
- const uint64_t val =
+ uint64_t val =
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
secAddr + rel.offset, *rel.sym, rel.expr);
switch (rel.expr) {
case R_RELAX_HINT:
+ continue;
+ case R_TLSDESC_PC:
+ // For R_RISCV_TLSDESC_HI20, store &got(sym)-PC to be used by the
+ // following two instructions L[DW] and ADDI.
+ if (rel.type == R_RISCV_TLSDESC_HI20)
+ tlsdescVal = val;
+ else
+ val = tlsdescVal;
break;
+ case R_RELAX_TLS_GD_TO_IE:
+ // Only R_RISCV_TLSDESC_HI20 reaches here. tlsdescVal will be finalized
+ // after we see R_RISCV_TLSDESC_ADD_LO12 in the R_RELAX_TLS_GD_TO_LE case.
+ // The net effect is that tlsdescVal will be smaller than `val` to take
+ // into account of NOP instructions (in the absence of R_RISCV_RELAX)
+ // before AUIPC.
+ tlsdescVal = val + rel.offset;
+ isToIe = true;
+ tlsdescToIe(loc, rel, val);
+ continue;
+ case R_RELAX_TLS_GD_TO_LE:
+ // See the comment in handleTlsRelocation. For TLSDESC=>IE,
+ // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12,CALL} also reach here. If isToIe is
+ // true, this is actually TLSDESC=>IE optimization.
+ if (rel.type == R_RISCV_TLSDESC_HI20) {
+ tlsdescVal = val;
+ isToIe = false;
+ } else {
+ if (isToIe && rel.type == R_RISCV_TLSDESC_ADD_LO12)
+ tlsdescVal -= rel.offset;
+ val = tlsdescVal;
+ }
+ if (isToIe)
+ tlsdescToIe(loc, rel, val);
+ else
+ tlsdescToLe(loc, rel, val);
+ continue;
case R_RISCV_LEB128:
if (i + 1 < size) {
const Relocation &rel1 = sec.relocs()[i + 1];
@@ -554,32 +672,12 @@ void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128");
return;
default:
- relocate(loc, rel, val);
break;
}
+ relocate(loc, rel, val);
}
}
-namespace {
-struct SymbolAnchor {
- uint64_t offset;
- Defined *d;
- bool end; // true for the anchor of st_value+st_size
-};
-} // namespace
-
-struct elf::RISCVRelaxAux {
- // This records symbol start and end offsets which will be adjusted according
- // to the nearest relocDeltas element.
- SmallVector<SymbolAnchor, 0> anchors;
- // For relocations[i], the actual offset is r_offset - (i ? relocDeltas[i-1] :
- // 0).
- std::unique_ptr<uint32_t[]> relocDeltas;
- // For relocations[i], the actual type is relocTypes[i].
- std::unique_ptr<RelType[]> relocTypes;
- SmallVector<uint32_t, 0> writes;
-};
-
static void initSymbolAnchors() {
SmallVector<InputSection *, 0> storage;
for (OutputSection *osec : outputSections) {
@@ -762,6 +860,14 @@ static bool relax(InputSection &sec) {
sec.relocs()[i + 1].type == R_RISCV_RELAX)
relaxHi20Lo12(sec, i, loc, r, remove);
break;
+ case R_RISCV_TLSDESC_HI20:
+ case R_RISCV_TLSDESC_LOAD_LO12:
+ // For LE or IE optimization, AUIPC and L[DW] are converted to a removable
+ // NOP.
+ if (r.expr != R_TLSDESC_PC && i + 1 != sec.relocs().size() &&
+ sec.relocs()[i + 1].type == R_RISCV_RELAX)
+ remove = 4;
+ break;
}
// For all anchors whose offsets are <= r.offset, they are preceded by
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index b6a317bc3b6d697..7e0cfc50605198e 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1274,26 +1274,31 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
if (config->emachine == EM_MIPS)
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
+ bool isRISCV = config->emachine == EM_RISCV;
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
config->shared) {
+ // R_RISCV_TLSDESC_{LOAD_LO12_I,ADD_LO12_I,CALL} reference a label. Do not
+ // set NEEDS_TLSDESC on the label.
if (expr != R_TLSDESC_CALL) {
- sym.setFlags(NEEDS_TLSDESC);
+ if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
+ sym.setFlags(NEEDS_TLSDESC);
c.addReloc({expr, type, offset, addend, &sym});
}
return 1;
}
// ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE
- // relaxation.
+ // optimizations.
+ // RISC-V supports TLSDESC to IE/LE optimizations.
// For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
// relaxation as well.
- bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
- config->emachine != EM_HEXAGON &&
- config->emachine != EM_LOONGARCH &&
- config->emachine != EM_RISCV &&
- !c.file->ppc64DisableTLSRelax;
+ bool toExecRelax =
+ !config->shared && config->emachine != EM_ARM &&
+ config->emachine != EM_HEXAGON && config->emachine != EM_LOONGARCH &&
+ !(isRISCV && expr != R_TLSDESC_PC && expr != R_TLSDESC_CALL) &&
+ !c.file->ppc64DisableTLSRelax;
// If we are producing an executable and the symbol is non-preemptable, it
// must be defined and the code sequence can be relaxed to use Local-Exec.
@@ -1347,8 +1352,12 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
return 1;
}
- // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+ // Global-Dynamic/TLSDESC can be relaxed to Initial-Exec or Local-Exec
// depending on the symbol being locally defined or not.
+ //
+ // R_RISCV_TLSDESC_{LOAD_LO12_I,ADD_LO12_I,CALL} reference a non-preemptible
+ // label, so the LE transition will be categorized as R_RELAX_TLS_GD_TO_LE.
+ // We fix the categorization in RISCV::relocateAlloc.
if (sym.isPreemptible) {
sym.setFlags(NEEDS_TLSGD_TO_IE);
c.addReloc({target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type,
diff --git a/lld/test/ELF/riscv-tlsdesc-gd-mixed.s b/lld/test/ELF/riscv-tlsdesc-gd-mixed.s
new file mode 100644
index 000000000000000..c0e91593ed9686d
--- /dev/null
+++ b/lld/test/ELF/riscv-tlsdesc-gd-mixed.s
@@ -0,0 +1,26 @@
+# REQUIRES: riscv
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck %s --check-prefix=RELA
+
+## Both TLSDESC and DTPMOD64/DTPREL64 should be present.
+# RELA: .rela.dyn {
+# RELA-NEXT: 0x[[#%X,ADDR:]] R_RISCV_TLSDESC a 0x0
+# RELA-NEXT: 0x[[#ADDR+16]] R_RISCV_TLS_DTPMOD64 a 0x0
+# RELA-NEXT: 0x[[#ADDR+24]] R_RISCV_TLS_DTPREL64 a 0x0
+# RELA-NEXT: }
+
+ la.tls.gd a0,a
+ call __tls_get_addr at plt
+
+.Ltlsdesc_hi0:
+ auipc a2, %tlsdesc_hi(a)
+ ld a3, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a2)
+ addi a0, a2, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+ jalr t0, 0(a3), %tlsdesc_call(.Ltlsdesc_hi0)
+
+.section .tbss,"awT", at nobits
+.globl a
+.zero 8
+a:
+.zero 4
diff --git a/lld/test/ELF/riscv-tlsdesc-relax.s b/lld/test/ELF/riscv-tlsdesc-relax.s
new file mode 100644
index 000000000000000..54cfac810990f66
--- /dev/null
+++ b/lld/test/ELF/riscv-tlsdesc-relax.s
@@ -0,0 +1,125 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o a.64.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax c.s -o c.64.o
+# RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so
+
+# RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so -z separate-code
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.so | FileCheck %s --check-prefix=GD64
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le -z separate-code
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.le | FileCheck %s --check-prefix=LE64
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie -z separate-code
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.ie | FileCheck %s --check-prefix=IE64
+
+# GD64: .got 00000018 00000000000020c0
+# GD64-LABEL: <_start>:
+# GD64-NEXT: jal {{.*}} <foo>
+# GD64-LABEL: <foo>:
+## &.got[c]-. = 0x20c0+8 - 0x1004 = 0x10c4
+# GD64: 1004: auipc a2, 0x1
+# GD64-NEXT: ld a3, 0xc4(a2)
+# GD64-NEXT: addi a0, a2, 0xc4
+# GD64-NEXT: jalr t0, 0x0(a3)
+# GD64-NEXT: c.add a0, tp
+# GD64-NEXT: jal {{.*}} <foo>
+# GD64-NEXT: auipc a4, 0x1
+# GD64-NEXT: ld a5, 0xae(a4)
+# GD64-NEXT: addi a0, a4, 0xae
+# GD64-NEXT: jalr t0, 0x0(a5)
+# GD64-NEXT: c.add a0, tp
+
+# LE64-LABEL: <_start>:
+# LE64-NEXT: jal {{.*}} <foo>
+# LE64-LABEL: <foo>:
+# LE64-NEXT: 11004: lui a0, 0x0
+# LE64-NEXT: addi a0, zero, 0xc
+# LE64-NEXT: c.add a0, tp
+# LE64-NEXT: jal {{.*}} <foo>
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: lui a0, 0x0
+# LE64-NEXT: addi a0, zero, 0xc
+# LE64-NEXT: c.add a0, tp
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: lui a0, 0x0
+# LE64-NEXT: addi a0, zero, 0xc
+# LE64-NEXT: c.add a0, tp
+
+# IE64: .got 00000010 00000000000120e0
+# IE64-LABEL: <_start>:
+# IE64-NEXT: jal {{.*}} <foo>
+# IE64-LABEL: <foo>:
+## &.got[c]-. = 0x120e0+8 - 0x11004 = 0x10e4
+# IE64-NEXT: 11004: auipc a0, 0x1
+# IE64-NEXT: ld a0, 0xe4(a0)
+# IE64-NEXT: c.add a0, tp
+# IE64-NEXT: jal {{.*}} <foo>
+# IE64-NEXT: addi zero, zero, 0x0
+## &.got[c]-. = 0x120e0+8 - 0x11016 = 0x10d2
+# IE64-NEXT: 11016: auipc a0, 0x1
+# IE64-NEXT: ld a0, 0xd2(a0)
+# IE64-NEXT: c.add a0, tp
+# IE64-NEXT: addi zero, zero, 0x0
+## &.got[c]-. = 0x120e0+8 - 0x11024 = 0x10c4
+# IE64-NEXT: 11024: auipc a0, 0x1
+# IE64-NEXT: ld a0, 0xc4(a0)
+# IE64-NEXT: c.add a0, tp
+
+#--- a.s
+.globl _start
+_start:
+.balign 16
+ call foo
+
+foo:
+.Ltlsdesc_hi0:
+.option norelax
+## All 4 instructions have an R_RISCV_RELAX.
+ auipc a2, %tlsdesc_hi(c)
+ .reloc .-4, R_RISCV_RELAX, 0
+ ld a3, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a2)
+ .reloc .-4, R_RISCV_RELAX, 0
+ addi a0, a2, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+ .reloc .-4, R_RISCV_RELAX, 0
+ jalr t0, 0(a3), %tlsdesc_call(.Ltlsdesc_hi0)
+ .reloc .-4, R_RISCV_RELAX, 0
+ add a0, a0, tp
+.option relax
+
+ call foo
+
+.Ltlsdesc_hi1:
+.option norelax
+## LD has an R_RISCV_RELAX.
+ auipc a4, %tlsdesc_hi(c)
+ ld a5, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a4)
+ .reloc .-4, R_RISCV_RELAX, 0
+ addi a0, a4, %tlsdesc_add_lo(.Ltlsdesc_hi1)
+ jalr t0, 0(a5), %tlsdesc_call(.Ltlsdesc_hi1)
+ add a0, a0, tp
+.option relax
+
+.Ltlsdesc_hi2:
+.option norelax
+## AUIPC has an R_RISCV_RELAX.
+ auipc a6, %tlsdesc_hi(c)
+ .reloc .-4, R_RISCV_RELAX, 0
+ ld a7, %tlsdesc_load_lo(.Ltlsdesc_hi2)(a6)
+ addi a0, a6, %tlsdesc_add_lo(.Ltlsdesc_hi2)
+ jalr t0, 0(a7), %tlsdesc_call(.Ltlsdesc_hi2)
+ add a0, a0, tp
+.option relax
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 3
+b:
+.zero 1
+
+#--- c.s
+.tbss
+.globl c
+c: .zero 4
diff --git a/lld/test/ELF/riscv-tlsdesc.s b/lld/test/ELF/riscv-tlsdesc.s
new file mode 100644
index 000000000000000..1759c6cc25583ec
--- /dev/null
+++ b/lld/test/ELF/riscv-tlsdesc.s
@@ -0,0 +1,192 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=riscv64 a.s -o a.64.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 c.s -o c.64.o
+# RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so
+# RUN: llvm-mc -filetype=obj -triple=riscv32 --defsym ELF32=1 a.s -o a.32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv32 --defsym ELF32=1 c.s -o c.32.o
+# RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so
+
+# RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so
+# RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.so | FileCheck %s --check-prefix=GD64
+
+# RUN: ld.lld -shared -z now a.64.o c.64.o -o rel.64.so -z rel
+# RUN: llvm-readobj -r -x .got rel.64.so | FileCheck --check-prefix=GD64-REL %s
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le
+# RUN: llvm-readelf -r a.64.le | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.le | FileCheck %s --check-prefix=LE64
+
+# RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie
+# RUN: llvm-readobj -r a.64.ie | FileCheck --check-prefix=IE64-RELA %s
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.64.ie | FileCheck %s --check-prefix=IE64
+
+## 32-bit code is mostly the same. We only test a few variants. The IE optimization uses the LW instruction.
+
+# RUN: ld.lld -shared -z now a.32.o c.32.o -o rel.32.so -z rel
+# RUN: llvm-readobj -r -x .got rel.32.so | FileCheck --check-prefix=GD32-REL %s
+# RUN: ld.lld -e 0 -z now a.32.o c.32.so -o a.32.ie
+# RUN: llvm-objdump --no-show-raw-insn -M no-aliases -h -d a.32.ie | FileCheck %s --check-prefix=IE32
+
+# GD64-RELA: .rela.dyn {
+# GD64-RELA-NEXT: 0x2408 R_RISCV_TLSDESC - 0x7FF
+# GD64-RELA-NEXT: 0x23E8 R_RISCV_TLSDESC a 0x0
+# GD64-RELA-NEXT: 0x23F8 R_RISCV_TLSDESC c 0x0
+# GD64-RELA-NEXT: }
+# GD64-RELA: Hex dump of section '.got':
+# GD64-RELA-NEXT: 0x000023e0 20230000 00000000 00000000 00000000 #
+# GD64-RELA-NEXT: 0x000023f0 00000000 00000000 00000000 00000000 .
+
+# GD64-REL: .rel.dyn {
+# GD64-REL-NEXT: 0x23F0 R_RISCV_TLSDESC -
+# GD64-REL-NEXT: 0x23D0 R_RISCV_TLSDESC a
+# GD64-REL-NEXT: 0x23E0 R_RISCV_TLSDESC c
+# GD64-REL-NEXT: }
+# GD64-REL: Hex dump of section '.got':
+# GD64-REL-NEXT: 0x000023c8 08230000 00000000 00000000 00000000 .
+# GD64-REL-NEXT: 0x000023d8 00000000 00000000 00000000 00000000 .
+# GD64-REL-NEXT: 0x000023e8 00000000 00000000 00000000 00000000 .
+# GD64-REL-NEXT: 0x000023f8 ff070000 00000000 .
+
+# GD32-REL: .rel.dyn {
+# GD32-REL-NEXT: 0x2274 R_RISCV_TLSDESC -
+# GD32-REL-NEXT: 0x2264 R_RISCV_TLSDESC a
+# GD32-REL-NEXT: 0x226C R_RISCV_TLSDESC c
+# GD32-REL-NEXT: }
+# GD32-REL: Hex dump of section '.got':
+# GD32-REL-NEXT: 0x00002260 00220000 00000000 00000000 00000000 .
+# GD32-REL-NEXT: 0x00002270 00000000 00000000 ff070000 .
+
+# GD64: .got 00000038 00000000000023e0
+
+## &.got[a]-. = 0x23e0+8 - 0x12e0 = 0x1108
+# GD64: 12e0: auipc a0, 0x1
+# GD64-NEXT: ld a1, 0x108(a0)
+# GD64-NEXT: addi a0, a0, 0x108
+# GD64-NEXT: jalr t0, 0x0(a1)
+# GD64-NEXT: add a0, a0, tp
+
+## &.got[b]-. = 0x23e0+40 - 0x12f4 = 0x1114
+# GD64-NEXT: 12f4: auipc a2, 0x1
+# GD64-NEXT: ld a3, 0x114(a2)
+# GD64-NEXT: addi a0, a2, 0x114
+# GD64-NEXT: jalr t0, 0x0(a3)
+# GD64-NEXT: add a0, a0, tp
+
+## &.got[c]-. = 0x23e0+24 - 0x1308 = 0x10f0
+# GD64-NEXT: 1308: auipc a4, 0x1
+# GD64-NEXT: ld a5, 0xf0(a4)
+# GD64-NEXT: addi a0, a4, 0xf0
+# GD64-NEXT: jalr t0, 0x0(a5)
+# GD64-NEXT: add a0, a0, tp
+
+# NOREL: no relocations
+
+## st_value(a) = 8
+# LE64-LABEL: <.text>:
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: lui a0, 0x0
+# LE64-NEXT: addi a0, zero, 0x8
+# LE64-NEXT: add a0, a0, tp
+## st_value(b) = 11
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: lui a0, 0x0
+# LE64-NEXT: addi a0, zero, 0x7ff
+# LE64-NEXT: add a0, a0, tp
+## st_value(c) = 12
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: addi zero, zero, 0x0
+# LE64-NEXT: lui a0, 0x1
+# LE64-NEXT: addi a0, a0, -0x800
+# LE64-NEXT: add a0, a0, tp
+
+# IE64-RELA: .rela.dyn {
+# IE64-RELA-NEXT: 0x123B0 R_RISCV_TLS_TPREL64 c 0x0
+# IE64-RELA-NEXT: }
+
+# IE64: .got 00000010 00000000000123a8
+
+## a and b are optimized to use LE. c is optimized to IE.
+# IE64-LABEL: <.text>:
+# IE64-NEXT: addi zero, zero, 0x0
+# IE64-NEXT: addi zero, zero, 0x0
+# IE64-NEXT: lui a0, 0x0
+# IE64-NEXT: addi a0, zero, 0x8
+# IE64-NEXT: add a0, a0, tp
+# IE64-NEXT: addi zero, zero, 0x0
+# IE64-NEXT: addi zero, zero, 0x0
+# IE64-NEXT: lui a0, 0x0
+# IE64-NEXT: addi a0, zero, 0x7ff
+# IE64-NEXT: add a0, a0, tp
+# IE64-NEXT: addi zero, zero, 0x0
+# IE64-NEXT: addi zero, zero, 0x0
+## &.got[c]-. = 0x123a8+8 - 0x112b8 = 0x10f8
+# IE64-NEXT: 112b8: auipc a0, 0x1
+# IE64-NEXT: ld a0, 0xf8(a0)
+# IE64-NEXT: add a0, a0, tp
+
+# IE32: .got 00000008 00012248
+
+# IE32-LABEL: <.text>:
+# IE32-NEXT: addi zero, zero, 0x0
+# IE32-NEXT: addi zero, zero, 0x0
+# IE32-NEXT: lui a0, 0x0
+# IE32-NEXT: addi a0, zero, 0x8
+# IE32-NEXT: add a0, a0, tp
+# IE32-NEXT: addi zero, zero, 0x0
+# IE32-NEXT: addi zero, zero, 0x0
+# IE32-NEXT: lui a0, 0x0
+# IE32-NEXT: addi a0, zero, 0x7ff
+# IE32-NEXT: add a0, a0, tp
+# IE32-NEXT: addi zero, zero, 0x0
+# IE32-NEXT: addi zero, zero, 0x0
+## &.got[c]-. = 0x12248+4 - 0x111cc = 0x1080
+# IE32-NEXT: 111cc: auipc a0, 0x1
+# IE32-NEXT: lw a0, 0x80(a0)
+# IE32-NEXT: add a0, a0, tp
+
+#--- a.s
+.macro load dst, src
+.ifdef ELF32
+lw \dst, \src
+.else
+ld \dst, \src
+.endif
+.endm
+
+.Ltlsdesc_hi0:
+ auipc a0, %tlsdesc_hi(a)
+ load a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+ addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+ jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+ add a0, a0, tp
+
+.Ltlsdesc_hi1:
+ auipc a2, %tlsdesc_hi(b)
+ load a3, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a2)
+ addi a0, a2, %tlsdesc_add_lo(.Ltlsdesc_hi1)
+ jalr t0, 0(a3), %tlsdesc_call(.Ltlsdesc_hi1)
+ add a0, a0, tp
+
+.Ltlsdesc_hi2:
+ auipc a4, %tlsdesc_hi(c)
+ load a5, %tlsdesc_load_lo(.Ltlsdesc_hi2)(a4)
+ addi a0, a4, %tlsdesc_add_lo(.Ltlsdesc_hi2)
+ jalr t0, 0(a5), %tlsdesc_call(.Ltlsdesc_hi2)
+ add a0, a0, tp
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 2039 ## Place b at 0x7ff
+b:
+.zero 1
+
+#--- c.s
+.tbss
+.globl c
+c: .zero 4
More information about the llvm-commits
mailing list