[clang-tools-extra] [llvm] [RISCV] Support Global Dynamic TLSDESC in the RISC-V backend (PR #66915)
Paul Kirth via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 18 11:27:32 PST 2023
https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/66915
>From ce9772dd519a62025cf545ded306bf40c75f2924 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/5] [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 | 4 +
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 97 +++++++++++++++++--
.../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 9 ++
.../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 6 +-
.../MCTargetDesc/RISCVELFObjectWriter.cpp | 15 +++
.../RISCV/MCTargetDesc/RISCVFixupKinds.h | 12 +++
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 46 +++++++++
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 18 ++++
.../Target/RISCV/MCTargetDesc/RISCVMCExpr.h | 4 +
llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 12 +++
.../Target/RISCV/RISCVExpandPseudoInsts.cpp | 53 ++++++++++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 23 ++++-
llvm/lib/Target/RISCV/RISCVISelLowering.h | 3 +
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 6 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 36 +++++++
llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 4 +
llvm/test/CodeGen/RISCV/tls-models.ll | 96 ++++++++++++++++++
17 files changed, 432 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
index 9a126df0153119..94420395fa0fad 100644
--- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def
@@ -55,3 +55,7 @@ ELF_RELOC(R_RISCV_SET32, 56)
ELF_RELOC(R_RISCV_32_PCREL, 57)
ELF_RELOC(R_RISCV_IRELATIVE, 58)
ELF_RELOC(R_RISCV_PLT32, 59)
+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/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 7d8d82e381313b..1303f5e85aeeb6 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -152,6 +152,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo instruction "la.tls.gd" used in global-dynamic TLS
// addressing.
void emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
+ void emitLoadTLSDescAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
// Helper to emit pseudo load/store instruction with a symbol.
void emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode, SMLoc IDLoc,
@@ -170,6 +171,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);
@@ -533,6 +540,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 {
@@ -584,7 +601,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.
@@ -837,7 +857,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>(); }
@@ -894,14 +916,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>(); }
@@ -1515,6 +1539,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");
@@ -3107,6 +3136,41 @@ void RISCVAsmParser::emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc,
RISCV::ADDI, IDLoc, Out);
}
+void RISCVAsmParser::emitLoadTLSDescAddress(MCInst &Inst, SMLoc IDLoc,
+ MCStreamer &Out) {
+ // The load TLS GD address pseudo-instruction "la.tlsdesc" is used in
+ // global-dynamic TLS model addressing of global symbols:
+ // la.tlsdesc rdest, symbol
+ // expands to
+ // TmpLabel: AUIPC rdest, %tlsdesc_hi(symbol)
+ // ADDI rdest, rdest, %pcrel_lo(TmpLabel)
+ MCOperand DestReg = Inst.getOperand(0);
+ const MCExpr *Symbol = Inst.getOperand(1).getExpr();
+
+ MCContext &Ctx = getContext();
+
+ MCSymbol *TmpLabel = Ctx.createNamedTempSymbol("pcrel_hi");
+ Out.emitLabel(TmpLabel);
+
+ const RISCVMCExpr *SymbolHi =
+ RISCVMCExpr::create(Symbol, RISCVMCExpr::VK_RISCV_TLSDESC_HI, Ctx);
+ emitToStreamer(
+ Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(SymbolHi));
+
+ const MCExpr *RefToLinkTmpLabel =
+ RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx),
+ RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO, Ctx);
+
+ emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
+ .addOperand(DestReg)
+ .addOperand(DestReg)
+ .addExpr(RefToLinkTmpLabel));
+
+ emitToStreamer(
+ Out,
+ MCInstBuilder(RISCV::JALR).addReg(RISCV::X5).addReg(RISCV::X5).addImm(0));
+}
+
void RISCVAsmParser::emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode,
SMLoc IDLoc, MCStreamer &Out,
bool HasTmpReg) {
@@ -3246,6 +3310,18 @@ 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(),
@@ -3443,6 +3519,9 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case RISCV::PseudoLA_TLS_GD:
emitLoadTLSGDAddress(Inst, IDLoc, Out);
return false;
+ case RISCV::PseudoLA_TLSDESC:
+ emitLoadTLSDescAddress(Inst, IDLoc, Out);
+ return false;
case RISCV::PseudoLB:
emitLoadStoreSymbol(Inst, RISCV::LB, IDLoc, Out, /*HasTmpReg=*/false);
return false;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index ca5aeb943c3be7..0b070e72c3ecb3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -80,6 +80,11 @@ 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");
@@ -118,6 +123,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;
}
@@ -390,6 +396,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:
@@ -399,6 +406,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)) {
@@ -502,6 +510,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 20ff26a39dc3b3..244d2e56c9fa2e 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -256,11 +256,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 0799267eaf7c76..bf73b82eaea880 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 f3d0841eb6bca6..3e8239ac08458b 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -71,6 +71,18 @@ enum Fixups {
// Used to generate an R_RISCV_ALIGN relocation, which indicates the linker
// should fixup the alignment after linker relaxation.
fixup_riscv_align,
+ // 20-bit fixup corresponding to %tlsdesc_hi(foo) for instructions like
+ // auipc
+ fixup_riscv_tlsdesc_hi20,
+ // 12-bit fixup corresponding to %tlsdesc_load_lo(foo) for instructions like
+ // addi
+ fixup_riscv_tlsdesc_load_lo12,
+ // 12-bit fixup corresponding to %tlsdesc_add_lo(foo) for instructions like
+ // addi
+ fixup_riscv_tlsdesc_add_lo12,
+ // Fixup representing a function call to TLS descriptor resolve function,
+ // %tlsdesc_call
+ 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 716c3ac14d116b..a0f6c74ba7d9f8 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;
@@ -150,6 +154,31 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI,
support::endian::write(CB, Binary, support::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()));
+ // Emit fixup_riscv_relax for jalr where the relax feature is enabled.
+ if (STI.hasFeature(RISCV::FeatureRelax)) {
+ const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx);
+ Fixups.push_back(MCFixup::create(
+ 0, Dummy, MCFixupKind(RISCV::fixup_riscv_relax), 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, support::little);
+}
+
// Expand PseudoAddTPRel to a simple ADD with the correct relocation.
void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI,
SmallVectorImpl<char> &CB,
@@ -299,6 +328,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) {
@@ -441,6 +474,19 @@ 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;
+ RelaxCandidate = true;
+ 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 d67351102bc1cd..35d0b7dfff3c39 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -81,6 +81,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;
@@ -121,6 +122,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);
}
@@ -147,6 +152,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:
@@ -195,6 +208,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;
}
@@ -208,6 +224,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 ee83bf0208ef46..fcc4c5c439645a 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 526520e6c5267d..d49a1b5ae2849e 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -695,6 +695,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 ff35a8fc9c5a1e..2b879d77a5f169 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -415,6 +415,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;
@@ -473,6 +477,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;
}
@@ -539,6 +545,53 @@ 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);
+
+ MachineInstr *TPAdd = BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg)
+ .addReg(RISCV::X10)
+ .addReg(RISCV::X4);
+
+ if (MI.hasOneMemOperand())
+ TPAdd->addMemOperand(*MF, *MI.memoperands_begin());
+ 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 0214bd1d7dda32..edcec8a984e690 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -50,6 +50,8 @@ using namespace llvm;
STATISTIC(NumTailCalls, "Number of tail calls");
+extern cl::opt<bool> EnableRISCVTLSDESC;
+
static cl::opt<unsigned> ExtensionMaxWebSize(
DEBUG_TYPE "-ext-max-web-size", cl::Hidden,
cl::desc("Give the maximum size (in number of nodes) of the web of "
@@ -6492,6 +6494,24 @@ SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
return LowerCallTo(CLI).first;
}
+SDValue
+RISCVTargetLowering::getGeneralDynamicTLSDescAddr(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 DAG.getNode(RISCVISD::LA_TLSDESC, DL, Ty, Addr);
+}
+
SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
@@ -6516,7 +6536,8 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
break;
case TLSModel::LocalDynamic:
case TLSModel::GeneralDynamic:
- Addr = getDynamicTLSAddr(N, DAG);
+ Addr = EnableRISCVTLSDESC ? getGeneralDynamicTLSDescAddr(N, DAG)
+ : getDynamicTLSAddr(N, DAG);
break;
}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index 815b9be47f5602..38be15fb288e8c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -57,6 +57,7 @@ enum NodeType : unsigned {
// Load address.
LA_TLS_GD,
+ LA_TLSDESC,
// Multiply high for signedxunsigned.
MULHSU,
@@ -845,6 +846,8 @@ class RISCVTargetLowering : public TargetLowering {
SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
bool UseGOT) const;
SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const;
+ SDValue getGeneralDynamicTLSDescAddr(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 816ceaf95607e7..713d1224cdc4bb 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1984,7 +1984,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 abbeff78b6e286..1c84ba5c056be4 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -95,6 +95,7 @@ def riscv_add_tprel : SDNode<"RISCVISD::ADD_TPREL",
def riscv_la_tls_ie : SDNode<"RISCVISD::LA_TLS_IE", SDTLoad,
[SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
def riscv_la_tls_gd : SDNode<"RISCVISD::LA_TLS_GD", SDTIntUnaryOp>;
+def riscv_la_tlsdesc : SDNode<"RISCVISD::LA_TLSDESC", SDTIntUnaryOp>;
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
@@ -1752,10 +1753,45 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0,
isAsmParserOnly = 1 in
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,
+ isAsmParserOnly = 1 in
+def PseudoLA_TLSDESC : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
+ "la.tlsdesc", "$dst, $src">;
def : Pat<(riscv_la_tls_gd tglobaltlsaddr:$in),
(PseudoLA_TLS_GD tglobaltlsaddr:$in)>;
+def : Pat<(riscv_la_tlsdesc tglobaltlsaddr:$in),
+ (PseudoLA_TLSDESC tglobaltlsaddr:$in)>;
+def : Pat<(riscv_la_tlsdesc texternalsym:$in),
+ (PseudoLA_TLSDESC texternalsym:$in)>;
+
+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
// There are single-instruction versions of these in Zbb, so disable these
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 30d559a4958c32..deaadb27477bb4 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -78,6 +78,10 @@ static cl::opt<bool> EnableRISCVDeadRegisterElimination(
" them with stores to x0"),
cl::init(true));
+cl::opt<bool> EnableRISCVTLSDESC("riscv-enable-tlsdesc",
+ cl::desc("Enable the tlsdesc for RISC-V"),
+ cl::Hidden);
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
RegisterTargetMachine<RISCVTargetMachine> X(getTheRISCV32Target());
RegisterTargetMachine<RISCVTargetMachine> Y(getTheRISCV64Target());
diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll
index d9b37cb0c7c22c..11e223068f9c3a 100644
--- a/llvm/test/CodeGen/RISCV/tls-models.ll
+++ b/llvm/test/CodeGen/RISCV/tls-models.ll
@@ -58,6 +58,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 +180,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 +247,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
}
>From 8a7ecf7ccdfd1c3e29fe5fe0513709dd386b7b0e Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 29 Nov 2023 21:35:03 +0000
Subject: [PATCH 2/5] !fixup Call and test checkPseudoTLSDESCCall
---
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 5 +++++
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 1 +
llvm/test/MC/RISCV/rv32i-invalid.s | 5 +++++
3 files changed, 11 insertions(+)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 1303f5e85aeeb6..7578405c6ba6ce 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -3310,6 +3310,7 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst,
return false;
}
+
bool RISCVAsmParser::checkPseudoTLSDESCCall(MCInst &Inst,
OperandVector &Operands) {
assert(Inst.getOpcode() == RISCV::PseudoTLSDESCCall && "Invalid instruction");
@@ -3577,6 +3578,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/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index edcec8a984e690..64719c115f8739 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -17269,6 +17269,7 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(ADD_TPREL)
NODE_NAME_CASE(LA_TLS_IE)
NODE_NAME_CASE(LA_TLS_GD)
+ NODE_NAME_CASE(LA_TLSDESC)
NODE_NAME_CASE(MULHSU)
NODE_NAME_CASE(SLLW)
NODE_NAME_CASE(SRAW)
diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s
index c5e0657b838094..c509883e69e640 100644
--- a/llvm/test/MC/RISCV/rv32i-invalid.s
+++ b/llvm/test/MC/RISCV/rv32i-invalid.s
@@ -188,3 +188,8 @@ addi a2, ft0, 24 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
# fence.tso accepts no operands
fence.tso rw, rw # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+
+.Ltlsdesc_hi0:
+jalr x5, 0(a1), %tlsdesc_hi(.Ltlsdesc_hi0) # CHECK: :[[@LINE]]:17: error: operand must be a symbol with %tlsdesc_call modifier
+jalr x1, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0) # CHECK: :[[@LINE]]:12: error: the output operand must be t0/x5 when using %tlsdesc_call modifier
+
>From 388dfac0191d2cad0569aa551e04e640f506868b Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 29 Nov 2023 22:13:06 +0000
Subject: [PATCH 3/5] fixup! clang-format
---
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 7578405c6ba6ce..40a54722b82971 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -3579,7 +3579,7 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
return true;
break;
case RISCV::PseudoTLSDESCCall:
- if(checkPseudoTLSDESCCall(Inst, Operands))
+ if (checkPseudoTLSDESCCall(Inst, Operands))
return true;
break;
case RISCV::PseudoSEXT_B:
>From 896ca77a7fea8cae9787659480dc131f5a3e3c34 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 18 Dec 2023 19:05:50 +0000
Subject: [PATCH 4/5] !fixup Address code differences after rebase
---
llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 3 ++-
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 5 +++--
llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp | 8 +++-----
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 2 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 6 ------
5 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 4a74eb20a1cfeb..ae362ae3bba223 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -87,7 +87,8 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"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_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},
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 532199d085ad6e..2b603e974e68e1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -158,7 +158,8 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI,
support::endian::write(CB, Binary, llvm::endianness::little);
}
-void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI, SmallVectorImpl<char> &CB,
+void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI,
+ SmallVectorImpl<char> &CB,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
MCOperand SrcSymbol = MI.getOperand(3);
@@ -180,7 +181,7 @@ void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI, SmallVectorImpl<cha
MCInstBuilder(RISCV::JALR).addReg(Link).addReg(Dest).addImm(Imm);
uint32_t Binary = getBinaryCodeForInstr(Call, Fixups, STI);
- support::endian::write(CB, Binary, support::little);
+ support::endian::write(CB, Binary, llvm::endianness::little);
}
// Expand PseudoAddTPRel to a simple ADD with the correct relocation.
diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
index 321e5777f61637..4b84bd567f6b34 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -578,12 +578,10 @@ bool RISCVPreRAExpandPseudo::expandLoadTLSDescAddress(
.addImm(0)
.addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_CALL);
- MachineInstr *TPAdd = BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg)
- .addReg(RISCV::X10)
- .addReg(RISCV::X4);
+ BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg)
+ .addReg(RISCV::X10)
+ .addReg(RISCV::X4);
- if (MI.hasOneMemOperand())
- TPAdd->addMemOperand(*MF, *MI.memoperands_begin());
MI.eraseFromParent();
return true;
}
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index cd5ef299361686..fbb8590a8278e0 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6860,7 +6860,7 @@ RISCVTargetLowering::getGeneralDynamicTLSDescAddr(GlobalAddressSDNode *N,
// 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 DAG.getNode(RISCVISD::LA_TLSDESC, DL, Ty, Addr);
+ return SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLSDESC, DL, Ty, Addr), 0);
}
SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 23f7bba1510ff6..00c2d17c8a4167 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1727,12 +1727,6 @@ let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 32, isCodeGenOnly = 0,
def PseudoLA_TLSDESC : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
"la.tlsdesc", "$dst, $src">;
-
-def : Pat<(riscv_la_tlsdesc tglobaltlsaddr:$in),
- (PseudoLA_TLSDESC tglobaltlsaddr:$in)>;
-def : Pat<(riscv_la_tlsdesc texternalsym:$in),
- (PseudoLA_TLSDESC texternalsym:$in)>;
-
def TLSDESCCallSymbol : AsmOperandClass {
let Name = "TLSDESCCallSymbol";
let RenderMethod = "addImmOperands";
>From df381c9f0aa4127081f3903b1ea61441a669dd7f Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 18 Dec 2023 19:20:55 +0000
Subject: [PATCH 5/5] !fixup Remove parsing for `la.tlsdesc`
Since this pseudo wasn't in the psABI, we shouldn't be emitting it
anywhere, and having the AsmParser handle it is a challenge without
introducing more operands, since it would need to know which registers
to use or have a way to scavenge registers. For now, we can leave the
pseudo-instruction as an implementation detail, with the understanding
that it shouldn't be emitted into the assembly output.
---
.../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 39 -------------------
1 file changed, 39 deletions(-)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 1ca4597bbbd1db..0f893b8eaf57f6 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -151,7 +151,6 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo instruction "la.tls.gd" used in global-dynamic TLS
// addressing.
void emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- void emitLoadTLSDescAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
// Helper to emit pseudo load/store instruction with a symbol.
void emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode, SMLoc IDLoc,
@@ -3203,41 +3202,6 @@ void RISCVAsmParser::emitLoadTLSGDAddress(MCInst &Inst, SMLoc IDLoc,
RISCV::ADDI, IDLoc, Out);
}
-void RISCVAsmParser::emitLoadTLSDescAddress(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // The load TLS GD address pseudo-instruction "la.tlsdesc" is used in
- // global-dynamic TLS model addressing of global symbols:
- // la.tlsdesc rdest, symbol
- // expands to
- // TmpLabel: AUIPC rdest, %tlsdesc_hi(symbol)
- // ADDI rdest, rdest, %pcrel_lo(TmpLabel)
- MCOperand DestReg = Inst.getOperand(0);
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
-
- MCContext &Ctx = getContext();
-
- MCSymbol *TmpLabel = Ctx.createNamedTempSymbol("pcrel_hi");
- Out.emitLabel(TmpLabel);
-
- const RISCVMCExpr *SymbolHi =
- RISCVMCExpr::create(Symbol, RISCVMCExpr::VK_RISCV_TLSDESC_HI, Ctx);
- emitToStreamer(
- Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(SymbolHi));
-
- const MCExpr *RefToLinkTmpLabel =
- RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx),
- RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO, Ctx);
-
- emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
- .addOperand(DestReg)
- .addOperand(DestReg)
- .addExpr(RefToLinkTmpLabel));
-
- emitToStreamer(
- Out,
- MCInstBuilder(RISCV::JALR).addReg(RISCV::X5).addReg(RISCV::X5).addImm(0));
-}
-
void RISCVAsmParser::emitLoadStoreSymbol(MCInst &Inst, unsigned Opcode,
SMLoc IDLoc, MCStreamer &Out,
bool HasTmpReg) {
@@ -3592,9 +3556,6 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case RISCV::PseudoLA_TLS_GD:
emitLoadTLSGDAddress(Inst, IDLoc, Out);
return false;
- case RISCV::PseudoLA_TLSDESC:
- emitLoadTLSDescAddress(Inst, IDLoc, Out);
- return false;
case RISCV::PseudoLB:
emitLoadStoreSymbol(Inst, RISCV::LB, IDLoc, Out, /*HasTmpReg=*/false);
return false;
More information about the llvm-commits
mailing list