[clang] [clang-tools-extra] [llvm] [lld] [RISC-V][LLD] Add Support for RISC-V TLSDESC Relocations (PR #66916)

Paul Kirth via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 4 15:45:21 PST 2024


https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/66916

>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 01/17] [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 02/17] !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 03/17] 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 04/17] !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 05/17] !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;

>From 50d3ffb5e25f965dcff93bb38d068d15d0b23cfe Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 18 Dec 2023 20:06:13 +0000
Subject: [PATCH 06/17] !fixup Add TODO to remove the cl::opt option

---
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 3eff9da05a1454..867a9378501f8c 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -80,6 +80,7 @@ static cl::opt<bool> EnableRISCVDeadRegisterElimination(
              " them with stores to x0"),
     cl::init(true));
 
+// TODO: This should be controlled by -mtls-dialect=<option>
 cl::opt<bool> EnableRISCVTLSDESC("riscv-enable-tlsdesc",
                                  cl::desc("Enable the tlsdesc for RISC-V"),
                                  cl::Hidden);

>From c54f7ac947c8639aa2dbf5a0e0239a342ac6e387 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 18 Dec 2023 20:10:35 +0000
Subject: [PATCH 07/17] !fixup Rename getGeneralDynamicTLSDescAddr to
 getTLSDescAddr

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 9 ++++-----
 llvm/lib/Target/RISCV/RISCVISelLowering.h   | 3 +--
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index fbb8590a8278e0..a5b7f7f1f01135 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6845,9 +6845,8 @@ SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
   return LowerCallTo(CLI).first;
 }
 
-SDValue
-RISCVTargetLowering::getGeneralDynamicTLSDescAddr(GlobalAddressSDNode *N,
-                                                  SelectionDAG &DAG) const {
+SDValue RISCVTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
+                                            SelectionDAG &DAG) const {
   SDLoc DL(N);
   EVT Ty = getPointerTy(DAG.getDataLayout());
   const GlobalValue *GV = N->getGlobal();
@@ -6887,8 +6886,8 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
     break;
   case TLSModel::LocalDynamic:
   case TLSModel::GeneralDynamic:
-    Addr = EnableRISCVTLSDESC ? getGeneralDynamicTLSDescAddr(N, DAG)
-                              : getDynamicTLSAddr(N, DAG);
+    Addr =
+        EnableRISCVTLSDESC ? getTLSDescAddr(N, DAG) : getDynamicTLSAddr(N, DAG);
     break;
   }
 
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index 308b2b7092924a..65f7d06494dd8f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -855,8 +855,7 @@ 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 getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const;
 
   SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;

>From 152b415d74a9e5a2ad232302031c5f47302d4041 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 3 Jan 2024 21:40:20 +0000
Subject: [PATCH 08/17] Don't set isAsmParserOnly bits in PseudoLA_TLSDESC

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 5796cfca3d41b7..9365ab461e2138 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1722,8 +1722,8 @@ 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
+
+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">;
 

>From 7ba52955052f508751778aad1df87d53aea61ebf Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 3 Jan 2024 21:41:05 +0000
Subject: [PATCH 09/17] Add back RUN lines to test removed in old rebase

---
 llvm/test/CodeGen/RISCV/tls-models.ll | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll
index 11e223068f9c3a..9cc9e8fd0d69dd 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 -riscv-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 -riscv-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 -riscv-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 -riscv-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

>From 1ba4890430b3e20c0799c0f6327ea75cfc12609e Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 3 Jan 2024 21:46:57 +0000
Subject: [PATCH 10/17] Test tlsdesc relocations in MC layer

---
 llvm/test/MC/RISCV/rv32-tlsdesc-valid.s | 17 +++++++++++++++++
 llvm/test/MC/RISCV/rv64-tlsdesc-valid.s | 16 ++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
 create mode 100644 llvm/test/MC/RISCV/rv64-tlsdesc-valid.s

diff --git a/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s b/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
new file mode 100644
index 00000000000000..78756a4d195d7a
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
@@ -0,0 +1,17 @@
+# RUN: llvm-mc -filetype=obj -triple riscv32 < %s | llvm-objdump -d -M no-aliases - | FileCheck %s
+
+start:                                  # @start
+# %bb.0:                                # %entry
+.Ltlsdesc_hi0:
+	auipc	a0, %tlsdesc_hi(unspecified)
+	#CHECK: auipc a0, 0x0
+	lw	a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+	#CHECK: lw a1, 0x0(a0)
+	addi	a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+	#CHECK: addi a0, a0, 0x0
+	jalr	t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+	#CHECK: jalr t0, 0x0(a1)
+	add	a0, a0, tp
+	#CHECK: add a0, a0, tp
+	ret
+
diff --git a/llvm/test/MC/RISCV/rv64-tlsdesc-valid.s b/llvm/test/MC/RISCV/rv64-tlsdesc-valid.s
new file mode 100644
index 00000000000000..8aba8aac79d702
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64-tlsdesc-valid.s
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -filetype=obj -triple riscv64 < %s | llvm-objdump -d -M no-aliases - | FileCheck %s
+
+start:                                  # @start
+# %bb.0:                                # %entry
+.Ltlsdesc_hi0:
+	auipc	a0, %tlsdesc_hi(unspecified)
+	#CHECK: auipc a0, 0x0
+	ld	a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+	#CHECK: ld a1, 0x0(a0)
+	addi	a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+	#CHECK: addi a0, a0, 0x0
+	jalr	t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+	#CHECK: jalr t0, 0x0(a1)
+	add	a0, a0, tp
+	#CHECK: add a0, a0, tp
+	ret

>From de4b9fc62c00003536543972624ec19aa1d92bb1 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 4 Jan 2024 00:15:54 +0000
Subject: [PATCH 11/17] Add test for invalid TLSDESC relocations

---
 llvm/test/MC/RISCV/tlsdesc-invalid.s | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 llvm/test/MC/RISCV/tlsdesc-invalid.s

diff --git a/llvm/test/MC/RISCV/tlsdesc-invalid.s b/llvm/test/MC/RISCV/tlsdesc-invalid.s
new file mode 100644
index 00000000000000..4619db6ace9e32
--- /dev/null
+++ b/llvm/test/MC/RISCV/tlsdesc-invalid.s
@@ -0,0 +1,14 @@
+# RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck %s
+# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s
+
+lga  x1, %tlsdesc_hi(1234) # CHECK: :[[@LINE]]:10: error: operand must be a bare symbol name
+lga  x1, %tlsdesc_hi(foo) # CHECK: :[[@LINE]]:10: error: operand must be a bare symbol name
+
+lw   a0, t0, %tlsdesc_load_lo(a_symbol) # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+lw   a0, t0, %tlsdesc_load_lo(a_symbol)(a4) # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+
+addi a0, t0, %tlsdesc_add_lo(a_symbol)(a4) # CHECK: :[[@LINE]]:40: error: invalid operand for instruction
+addi a0, %tlsdesc_add_lo(a_symbol) # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+
+jalr t0, a0, %tlsdesc_call(a_symbol) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+jalr t0, 12345(a1), %tlsdesc_call(a_symbol) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]

>From d60118ce3079cc64036cbb142a57819e96ed424a Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 4 Jan 2024 00:18:11 +0000
Subject: [PATCH 12/17] Remove trailing whitespace

---
 llvm/test/MC/RISCV/rv32-tlsdesc-valid.s | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s b/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
index 78756a4d195d7a..fd42f3892632db 100644
--- a/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
+++ b/llvm/test/MC/RISCV/rv32-tlsdesc-valid.s
@@ -14,4 +14,3 @@ start:                                  # @start
 	add	a0, a0, tp
 	#CHECK: add a0, a0, tp
 	ret
-

>From aa301e3747dc6141fcf529441e801e2017b2e384 Mon Sep 17 00:00:00 2001
From: Paul Kirth <pk1574 at gmail.com>
Date: Thu, 4 Jan 2024 21:58:20 +0000
Subject: [PATCH 13/17] Update error string to match checks

---
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp |  2 +-
 llvm/test/MC/RISCV/corev/XCVelw-invalid.s     |  2 +-
 llvm/test/MC/RISCV/corev/XCVmem-invalid.s     | 26 +++++++++----------
 llvm/test/MC/RISCV/insn-invalid.s             |  2 +-
 llvm/test/MC/RISCV/rv32d-invalid.s            |  4 +--
 llvm/test/MC/RISCV/rv32f-invalid.s            |  4 +--
 llvm/test/MC/RISCV/rv32i-invalid.s            | 14 +++++-----
 llvm/test/MC/RISCV/rv32zfbfmin-invalid.s      |  4 +--
 llvm/test/MC/RISCV/rv32zfh-invalid.s          |  4 +--
 llvm/test/MC/RISCV/rv32zfhmin-invalid.s       |  4 +--
 llvm/test/MC/RISCV/rv64i-invalid.s            |  6 ++---
 llvm/test/MC/RISCV/rv64zdinx-invalid.s        |  2 +-
 llvm/test/MC/RISCV/rv64zfh-invalid.s          |  4 +--
 llvm/test/MC/RISCV/rvi-pseudos-invalid.s      |  2 +-
 llvm/test/MC/RISCV/tlsdesc-invalid.s          |  8 +++---
 15 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 80ad3dd88590e9..2b29905f876f4e 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1515,7 +1515,7 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidSImm12:
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1,
-        "operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an "
+        "operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an "
         "integer in the range");
   case Match_InvalidSImm12Lsb0:
     return generateImmOutOfRangeError(
diff --git a/llvm/test/MC/RISCV/corev/XCVelw-invalid.s b/llvm/test/MC/RISCV/corev/XCVelw-invalid.s
index 24870904ac49b1..70011d85d22e74 100644
--- a/llvm/test/MC/RISCV/corev/XCVelw-invalid.s
+++ b/llvm/test/MC/RISCV/corev/XCVelw-invalid.s
@@ -8,7 +8,7 @@ cv.elw 0, 0(x6)
 # CHECK-ERROR: invalid operand for instruction
 
 cv.elw x12, 2048(x6)
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.elw x12, x1(2047)
 # CHECK-ERROR: unexpected token
diff --git a/llvm/test/MC/RISCV/corev/XCVmem-invalid.s b/llvm/test/MC/RISCV/corev/XCVmem-invalid.s
index e71cd7daa890e6..959675deb19d21 100644
--- a/llvm/test/MC/RISCV/corev/XCVmem-invalid.s
+++ b/llvm/test/MC/RISCV/corev/XCVmem-invalid.s
@@ -11,10 +11,10 @@ cv.lb 0, (0), t2
 # CHECK-ERROR: invalid operand for instruction
 
 cv.lb t0, (t1), -2049
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lb t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lb t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -41,10 +41,10 @@ cv.lbu 0, (0), t0
 # CHECK-ERROR: invalid operand for instruction
 
 cv.lbu t0, (t1), -2049
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lbu t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lbu t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -71,10 +71,10 @@ cv.lh 0, (0), t2
 # CHECK-ERROR: invalid operand for instruction
 
 cv.lh t0, (t1), -2049
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lh t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lh t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -104,10 +104,10 @@ cv.lhu 0, 0(t1)
 # CHECK-ERROR: invalid operand for instruction
 
 cv.lhu t0, (t1), -2049
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lhu t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lhu t0, (0), t1
 # CHECK-ERROR: operands must be register and register 
@@ -137,10 +137,10 @@ cv.lw 0, (0), t2
 # CHECK-ERROR: invalid operand for instruction
 
 cv.lw t0, (t1), -2049
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lw t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.lw t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -170,7 +170,7 @@ cv.sb t0, 0(t1)
 # CHECK-ERROR: operands must be register and register
 
 cv.sb t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.sb t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -191,7 +191,7 @@ cv.sh t0, 0(t1)
 # CHECK-ERROR: operands must be register and register
 
 cv.sh t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.sh t0, (0), t1
 # CHECK-ERROR: operands must be register and register
@@ -212,7 +212,7 @@ cv.sw t0, 0(t1)
 # CHECK-ERROR: operands must be register and register
 
 cv.sw t0, (t1), 2048
-# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+# CHECK-ERROR: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 cv.sw t0, (0), t1
 # CHECK-ERROR: operands must be register and register
diff --git a/llvm/test/MC/RISCV/insn-invalid.s b/llvm/test/MC/RISCV/insn-invalid.s
index 32ebd6867377c2..0f99a3e7adc980 100644
--- a/llvm/test/MC/RISCV/insn-invalid.s
+++ b/llvm/test/MC/RISCV/insn-invalid.s
@@ -9,7 +9,7 @@
 .insn i  0x13,  0,  a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction
 
 .insn r  0x33,  0,  0, a0, 13 # CHECK: :[[@LINE]]:28: error: invalid operand for instruction
-.insn i  0x13,  0, a0, a1, a2 # CHECK: :[[@LINE]]:28: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+.insn i  0x13,  0, a0, a1, a2 # CHECK: :[[@LINE]]:28: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 .insn q  0x13,  0,  a0, a1, 13, 14 # CHECK: :[[@LINE]]:7: error: invalid instruction format
 
diff --git a/llvm/test/MC/RISCV/rv32d-invalid.s b/llvm/test/MC/RISCV/rv32d-invalid.s
index ee363ec7db79cb..5b38a073a71757 100644
--- a/llvm/test/MC/RISCV/rv32d-invalid.s
+++ b/llvm/test/MC/RISCV/rv32d-invalid.s
@@ -2,8 +2,8 @@
 
 # Out of range immediates
 ## simm12
-fld ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsd ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+fld ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsd ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Memory operand not formatted correctly
 fld ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv32f-invalid.s b/llvm/test/MC/RISCV/rv32f-invalid.s
index f2d368071a0bbb..7897897c773596 100644
--- a/llvm/test/MC/RISCV/rv32f-invalid.s
+++ b/llvm/test/MC/RISCV/rv32f-invalid.s
@@ -2,8 +2,8 @@
 
 # Out of range immediates
 ## simm12
-flw ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsw ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+flw ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsw ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Memory operand not formatted correctly
 flw ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv32i-invalid.s b/llvm/test/MC/RISCV/rv32i-invalid.s
index c509883e69e640..9075fc2c974972 100644
--- a/llvm/test/MC/RISCV/rv32i-invalid.s
+++ b/llvm/test/MC/RISCV/rv32i-invalid.s
@@ -17,8 +17,8 @@ csrrsi t1, 999, 32 # CHECK: :[[@LINE]]:17: error: immediate must be an integer i
 csrrci x0, 43, -90 # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31]
 
 ## simm12
-ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 ## uimm12
 csrrw a0, -1, a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
@@ -67,11 +67,11 @@ csrrsi t1, 999, %pcrel_lo(4) # CHECK: :[[@LINE]]:17: error: immediate must be an
 csrrci x0, 43, %pcrel_lo(d) # CHECK: :[[@LINE]]:16: error: immediate must be an integer in the range [0, 31]
 
 ## simm12
-ori a0, a1, %hi(foo) # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-andi ra, sp, %pcrel_hi(123) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-xori a2, a3, %hi(345) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-add a1, a2, (a3) # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-add a1, a2, foo # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+ori a0, a1, %hi(foo) # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+andi ra, sp, %pcrel_hi(123) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+xori a2, a3, %hi(345) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+add a1, a2, (a3) # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+add a1, a2, foo # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 ## uimm12
 csrrw a0, %lo(1), a0 # CHECK: :[[@LINE]]:11: error: immediate must be an integer in the range [0, 4095]
diff --git a/llvm/test/MC/RISCV/rv32zfbfmin-invalid.s b/llvm/test/MC/RISCV/rv32zfbfmin-invalid.s
index b7b5a0a84b32df..967aa14d603276 100644
--- a/llvm/test/MC/RISCV/rv32zfbfmin-invalid.s
+++ b/llvm/test/MC/RISCV/rv32zfbfmin-invalid.s
@@ -5,8 +5,8 @@
 
 # Out of range immediates
 ## simm12
-flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Memory operand not formatted correctly
 flh ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv32zfh-invalid.s b/llvm/test/MC/RISCV/rv32zfh-invalid.s
index efa5e871616f66..f265ae40c0249a 100644
--- a/llvm/test/MC/RISCV/rv32zfh-invalid.s
+++ b/llvm/test/MC/RISCV/rv32zfh-invalid.s
@@ -3,8 +3,8 @@
 
 # Out of range immediates
 ## simm12
-flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Memory operand not formatted correctly
 flh ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv32zfhmin-invalid.s b/llvm/test/MC/RISCV/rv32zfhmin-invalid.s
index 8fe90d4f7100c2..1549803cd9a71b 100644
--- a/llvm/test/MC/RISCV/rv32zfhmin-invalid.s
+++ b/llvm/test/MC/RISCV/rv32zfhmin-invalid.s
@@ -5,8 +5,8 @@
 
 # Out of range immediates
 ## simm12
-flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Memory operand not formatted correctly
 flh ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv64i-invalid.s b/llvm/test/MC/RISCV/rv64i-invalid.s
index deb8ea54fde35e..a176d0608062c5 100644
--- a/llvm/test/MC/RISCV/rv64i-invalid.s
+++ b/llvm/test/MC/RISCV/rv64i-invalid.s
@@ -12,8 +12,8 @@ srli a0, a0, -1 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in t
 srai a0, a0, -19 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 63]
 
 ## simm12
-addiw a0, a1, -2049 # CHECK: :[[@LINE]]:15: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-ld ra, 2048(sp) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+addiw a0, a1, -2049 # CHECK: :[[@LINE]]:15: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+ld ra, 2048(sp) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Illegal operand modifier
 ## uimm5
@@ -27,4 +27,4 @@ srli a0, a0, %lo(a) # CHECK: :[[@LINE]]:14: error: immediate must be an integer
 srai a0, a0, %hi(2) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 63]
 
 ## simm12
-addiw a0, a1, %hi(foo) # CHECK: :[[@LINE]]:15: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+addiw a0, a1, %hi(foo) # CHECK: :[[@LINE]]:15: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
diff --git a/llvm/test/MC/RISCV/rv64zdinx-invalid.s b/llvm/test/MC/RISCV/rv64zdinx-invalid.s
index 31414d87e6f4e5..79f979fee52abf 100644
--- a/llvm/test/MC/RISCV/rv64zdinx-invalid.s
+++ b/llvm/test/MC/RISCV/rv64zdinx-invalid.s
@@ -2,7 +2,7 @@
 
 # Not support float registers
 fld fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'D' (Double-Precision Floating-Point){{$}}
-ld a0, -2049(a1) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+ld a0, -2049(a1) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Invalid instructions
 fsd a5, 12(sp) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rv64zfh-invalid.s b/llvm/test/MC/RISCV/rv64zfh-invalid.s
index d6835746f0a8cf..fb770973401f62 100644
--- a/llvm/test/MC/RISCV/rv64zfh-invalid.s
+++ b/llvm/test/MC/RISCV/rv64zfh-invalid.s
@@ -3,8 +3,8 @@
 
 # Out of range immediates
 ## simm12
-flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
+fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 
 # Integer registers where FP regs are expected
 fcvt.l.h ft0, a0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
diff --git a/llvm/test/MC/RISCV/rvi-pseudos-invalid.s b/llvm/test/MC/RISCV/rvi-pseudos-invalid.s
index c10bef53732b23..ca52e213ed2c85 100644
--- a/llvm/test/MC/RISCV/rvi-pseudos-invalid.s
+++ b/llvm/test/MC/RISCV/rvi-pseudos-invalid.s
@@ -11,7 +11,7 @@ lga x1, %lo(1234) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol na
 lga x1, %hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
 lga x1, %lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name
 
-sw a2, %hi(a_symbol), a3 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+sw a2, %hi(a_symbol), a3 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an integer in the range [-2048, 2047]
 sw a2, %lo(a_symbol), a3 # CHECK: :[[@LINE]]:23: error: invalid operand for instruction
 sw a2, %lo(a_symbol)(a4), a3 # CHECK: :[[@LINE]]:27: error: invalid operand for instruction
 
diff --git a/llvm/test/MC/RISCV/tlsdesc-invalid.s b/llvm/test/MC/RISCV/tlsdesc-invalid.s
index 4619db6ace9e32..5b40b9b50585c4 100644
--- a/llvm/test/MC/RISCV/tlsdesc-invalid.s
+++ b/llvm/test/MC/RISCV/tlsdesc-invalid.s
@@ -1,8 +1,8 @@
 # RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck %s
 # RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s
 
-lga  x1, %tlsdesc_hi(1234) # CHECK: :[[@LINE]]:10: error: operand must be a bare symbol name
-lga  x1, %tlsdesc_hi(foo) # CHECK: :[[@LINE]]:10: error: operand must be a bare symbol name
+auipc x1, %tlsdesc_call(foo) # CHECK: :[[@LINE]]:11: 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) # CHECK: :[[@LINE]]:11: 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) # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
 lw   a0, t0, %tlsdesc_load_lo(a_symbol)(a4) # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
@@ -10,5 +10,5 @@ lw   a0, t0, %tlsdesc_load_lo(a_symbol)(a4) # CHECK: :[[@LINE]]:14: error: inval
 addi a0, t0, %tlsdesc_add_lo(a_symbol)(a4) # CHECK: :[[@LINE]]:40: error: invalid operand for instruction
 addi a0, %tlsdesc_add_lo(a_symbol) # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
 
-jalr t0, a0, %tlsdesc_call(a_symbol) # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
-jalr t0, 12345(a1), %tlsdesc_call(a_symbol) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
+jalr x5, 0(a1), %tlsdesc_hi(a_symbol) # CHECK: :[[@LINE]]:17: error: operand must be a symbol with %tlsdesc_call modifier
+jalr x1, 0(a1), %tlsdesc_call(a_symbol) # CHECK: :[[@LINE]]:12: error: the output operand must be t0/x5 when using %tlsdesc_call modifier

>From dcce10110017a19ca36e7a4aac6d829c53a88bd1 Mon Sep 17 00:00:00 2001
From: Paul Kirth <pk1574 at gmail.com>
Date: Thu, 4 Jan 2024 22:16:09 +0000
Subject: [PATCH 14/17] Fix documentation for fixup_riscv_tlsdesc_load_lo12

---
 llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
index 47e8ca01b480d5..8304826830dde4 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -75,7 +75,7 @@ enum Fixups {
   // auipc
   fixup_riscv_tlsdesc_hi20,
   // 12-bit fixup corresponding to %tlsdesc_load_lo(foo) for instructions like
-  // addi
+  // lw
   fixup_riscv_tlsdesc_load_lo12,
   // 12-bit fixup corresponding to %tlsdesc_add_lo(foo) for instructions like
   // addi

>From cde5cba5d227e2bfb85a3fd0db19ca7a702ce6a8 Mon Sep 17 00:00:00 2001
From: Paul Kirth <pk1574 at gmail.com>
Date: Thu, 4 Jan 2024 22:21:57 +0000
Subject: [PATCH 15/17] Run clang-format on patch

---
 llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 2b29905f876f4e..6b6699f91d6263 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1515,7 +1515,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidSImm12:
     return generateImmOutOfRangeError(
         Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1,
-        "operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi modifier or an "
+        "operand must be a symbol with %lo/%pcrel_lo/%tprel_lo/%tlsdesc_hi "
+        "modifier or an "
         "integer in the range");
   case Match_InvalidSImm12Lsb0:
     return generateImmOutOfRangeError(

>From 2e3d34ae8e8faa2ade617caced8e94c3ae58ead3 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Fri, 15 Sep 2023 20:56:30 +0000
Subject: [PATCH 16/17] [RISCV] Support RISC-V TLSDESC in LLD

This patch adds support for RISC-V TLSDESC relocations, as described in
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373.

It does not attempt to handle relaxation for these cases, which will be
handled separately.
---
 lld/ELF/Arch/RISCV.cpp          | 20 +++++++++++++++
 lld/ELF/InputSection.cpp        |  1 +
 lld/ELF/Relocations.cpp         |  4 +--
 lld/ELF/Relocations.h           |  4 +++
 lld/ELF/Writer.cpp              |  3 ++-
 lld/test/ELF/riscv-tlsdesc-le.s | 43 +++++++++++++++++++++++++++++++++
 6 files changed, 72 insertions(+), 3 deletions(-)
 create mode 100644 lld/test/ELF/riscv-tlsdesc-le.s

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 898e3e45b9e724..118bbf247cb5a8 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -43,6 +43,7 @@ class RISCV final : public TargetInfo {
                      const uint8_t *loc) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+  RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
   bool relaxOnce(int pass) const override;
 };
 
@@ -119,6 +120,8 @@ RISCV::RISCV() {
   }
   gotRel = symbolicRel;
 
+  tlsDescRel = R_RISCV_TLSDESC_CALL;
+
   // .got[0] = _DYNAMIC
   gotHeaderEntriesNum = 1;
 
@@ -297,6 +300,13 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
     return R_TLSGD_PC;
   case R_RISCV_TLS_GOT_HI20:
     return R_GOT_PC;
+  case R_RISCV_TLSDESC_HI20:
+    return R_TLSDESC_PC;
+  case R_RISCV_TLSDESC_LOAD_LO12:
+  case R_RISCV_TLSDESC_ADD_LO12:
+    return R_TLSDESC;
+  case R_RISCV_TLSDESC_CALL:
+    return R_TLSDESC_CALL;
   case R_RISCV_TPREL_HI20:
   case R_RISCV_TPREL_LO12_I:
   case R_RISCV_TPREL_LO12_S:
@@ -418,6 +428,7 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   case R_RISCV_PCREL_HI20:
   case R_RISCV_TLS_GD_HI20:
   case R_RISCV_TLS_GOT_HI20:
+  case R_RISCV_TLSDESC_HI20:
   case R_RISCV_TPREL_HI20:
   case R_RISCV_HI20: {
     uint64_t hi = val + 0x800;
@@ -428,6 +439,8 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
 
   case R_RISCV_PCREL_LO12_I:
   case R_RISCV_TPREL_LO12_I:
+  case R_RISCV_TLSDESC_LOAD_LO12:
+  case R_RISCV_TLSDESC_ADD_LO12:
   case R_RISCV_LO12_I: {
     uint64_t hi = (val + 0x800) >> 12;
     uint64_t lo = val - (hi << 12);
@@ -515,6 +528,13 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   }
 }
 
+RelExpr RISCV::adjustTlsExpr(RelType type, RelExpr expr) const {
+  if (expr == R_RELAX_TLS_GD_TO_IE) {
+    return R_RELAX_TLS_GD_TO_IE_ABS;
+  }
+  return expr;
+}
+
 namespace {
 struct SymbolAnchor {
   uint64_t offset;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 5dfb57fda432e0..288d288e08a1e8 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -850,6 +850,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
     return sym.getSize() + a;
   case R_TLSDESC:
     return in.got->getTlsDescAddr(sym) + a;
+  case R_RISCV_TLSDESC_HI:
   case R_TLSDESC_PC:
     return in.got->getTlsDescAddr(sym) + a - p;
   case R_TLSDESC_GOTPLT:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 210b4d1eb1a7a6..68ff1d6e9809ea 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1269,7 +1269,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
     return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
-            R_TLSDESC_GOTPLT>(expr) &&
+            R_TLSDESC_GOTPLT, R_RISCV_TLSDESC_HI>(expr) &&
       config->shared) {
     if (expr != R_TLSDESC_CALL) {
       sym.setFlags(NEEDS_TLSDESC);
@@ -1333,7 +1333,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
             R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
-            R_LOONGARCH_TLSGD_PAGE_PC>(expr)) {
+            R_LOONGARCH_TLSGD_PAGE_PC, R_RISCV_TLSDESC_HI>(expr)) {
     if (!toExecRelax) {
       sym.setFlags(NEEDS_TLSGD);
       c.addReloc({expr, type, offset, addend, &sym});
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index cfb9092149f3e0..9a24fe8a219dab 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -103,6 +103,10 @@ enum RelExpr {
   R_RISCV_ADD,
   R_RISCV_LEB128,
   R_RISCV_PC_INDIRECT,
+  R_RISCV_TLSDESC_HI,
+  R_RISCV_TLSDESC_LOAD_LO,
+  R_RISCV_TLSDESC_ADD_LO,
+  R_RISCV_TLSDESC_CALLER,
   // Same as R_PC but with page-aligned semantics.
   R_LOONGARCH_PAGE_PC,
   // Same as R_PLT_PC but with page-aligned semantics.
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a84e4864ab0e5a..d1b24c2b181319 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1943,7 +1943,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
       }
     }
 
-    if (config->emachine == EM_386 || config->emachine == EM_X86_64) {
+    if (config->emachine == EM_386 || config->emachine == EM_X86_64 ||
+        config->emachine == EM_RISCV) {
       // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
       // way that:
       //
diff --git a/lld/test/ELF/riscv-tlsdesc-le.s b/lld/test/ELF/riscv-tlsdesc-le.s
new file mode 100644
index 00000000000000..6aa670cffb59b8
--- /dev/null
+++ b/lld/test/ELF/riscv-tlsdesc-le.s
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple=riscv64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s
+// RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=REL %s
+
+//      CHECK: 00000000000012d8 <_start>:
+// CHECK-NEXT:    12d8:       auipc   a0, 1
+// CHECK-NEXT:    12dc:       ld      a1, 920(a0)
+// CHECK-NEXT:    12e0:       addi    a0, a0, 920
+// CHECK-NEXT:    12e4:       jalr    t0, a1
+// CHECK-NEXT:    12e8:       add     a0, a0, tp
+// CHECK-NEXT:    12ec:       ret
+
+//      REL: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries
+//      REL: R_RISCV_TLSDESC_CALL ffffffffffffffe8
+// REL-NEXT: R_RISCV_TLSDESC_CALL 0
+
+	.text
+	.attribute	4, 16
+	.attribute	5, "rv64i2p1"
+	.file	"<stdin>"
+	.globl	_start                              # -- Begin function _start
+	.p2align	2
+	.type	_start, at function
+_start:                                     # @_start
+# %bb.0:                                # %entry
+.Ltlsdesc_hi0:
+	auipc	a0, %tlsdesc_hi(unspecified)
+	ld	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
+	ret
+.Lfunc_end0:
+	.size	_start, .Lfunc_end0-_start
+                                        # -- End function
+	.section	".note.GNU-stack","", at progbits
+
+        .section .tbss,"awT", at nobits
+        .p2align 2
+
+unspecified:
+        .zero    4

>From dc965afc1cc2fad53a46617ef65f6994572c54d8 Mon Sep 17 00:00:00 2001
From: Paul Kirth <pk1574 at gmail.com>
Date: Thu, 4 Jan 2024 23:34:44 +0000
Subject: [PATCH 17/17] Add checks both local and global accesses in test

---
 lld/test/ELF/riscv-tlsdesc-le.s | 45 +++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/lld/test/ELF/riscv-tlsdesc-le.s b/lld/test/ELF/riscv-tlsdesc-le.s
index 6aa670cffb59b8..21541ee5977019 100644
--- a/lld/test/ELF/riscv-tlsdesc-le.s
+++ b/lld/test/ELF/riscv-tlsdesc-le.s
@@ -3,17 +3,23 @@
 // RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s
 // RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=REL %s
 
-//      CHECK: 00000000000012d8 <_start>:
-// CHECK-NEXT:    12d8:       auipc   a0, 1
-// CHECK-NEXT:    12dc:       ld      a1, 920(a0)
-// CHECK-NEXT:    12e0:       addi    a0, a0, 920
-// CHECK-NEXT:    12e4:       jalr    t0, a1
-// CHECK-NEXT:    12e8:       add     a0, a0, tp
-// CHECK-NEXT:    12ec:       ret
+//      CHECK: 0000000000001318 <_start>:
+// CHECK-NEXT:    1318:       auipc   a0, 1
+// CHECK-NEXT:    131c:       ld      a1, 1008(a0)
+// CHECK-NEXT:    1320:       addi    a0, a0, 1008
+// CHECK-NEXT:    1324:       jalr    t0, a1
+// CHECK-NEXT:    1328:       add     a0, a0, tp
+// CHECK-NEXT:    132c:       auipc   a0, 1
+// CHECK-NEXT:    1330:       ld      a1, 1040(a0)
+// CHECK-NEXT:    1334:       addi    a0, a0, 1040
+// CHECK-NEXT:    1338:       jalr    t0, a1
+// CHECK-NEXT:    133c:       add     a0, a0, tp
+// CHECK-NEXT:    1340:       ret
 
-//      REL: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries
-//      REL: R_RISCV_TLSDESC_CALL ffffffffffffffe8
-// REL-NEXT: R_RISCV_TLSDESC_CALL 0
+//      REL: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries
+//      REL: R_RISCV_TLSDESC_CALL              ffffffffffffffd4
+// REL-NEXT: R_RISCV_TLSDESC_CALL              4
+// REL-NEXT: R_RISCV_TLSDESC_CALL              ffffffffffffffe8
 
 	.text
 	.attribute	4, 16
@@ -23,21 +29,32 @@
 	.p2align	2
 	.type	_start, at function
 _start:                                     # @_start
-# %bb.0:                                # %entry
+// access local variable
 .Ltlsdesc_hi0:
 	auipc	a0, %tlsdesc_hi(unspecified)
 	ld	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
+
+// access global variable
+.Ltlsdesc_hi1:
+	auipc	a0, %tlsdesc_hi(unspecified)
+	ld	a1, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a0)
+	addi	a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi1)
+	jalr	t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi1)
+	add	a0, a0, tp
 	ret
 .Lfunc_end0:
 	.size	_start, .Lfunc_end0-_start
                                         # -- End function
 	.section	".note.GNU-stack","", at progbits
 
-        .section .tbss,"awT", at nobits
-        .p2align 2
+	.section .tbss,"awT", at nobits
+	.p2align 2
+	.global v1
+v1:
+	.zero    4
 
 unspecified:
-        .zero    4
+	.zero    4



More information about the cfe-commits mailing list