From cdf380485d8bfe505f75880b4c800225c2b5d0d8 Mon Sep 17 00:00:00 2001 From: Paul Kirth Date: Tue, 19 Sep 2023 20:53:54 +0000 Subject: [PATCH] [RISCV] Support Global Dynamic TLSDESC in the RISC-V backend This patch adds basic TLSDESC support for the global dynamic case in the RISC-V backend by adding new relocation types for TLSDESC, as prescribed in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373. We also add a new pseudo instruction to simplify code generation. Possible improvements for the local dynamic case will be addressed in separate patches. The current implementation is only enabled when passing the -riscv-enable-tlsdesc flag. --- .../llvm/BinaryFormat/ELFRelocs/RISCV.def | 5 + llvm/include/llvm/CodeGen/CommandFlags.h | 3 + llvm/include/llvm/Target/TargetMachine.h | 3 + llvm/include/llvm/Target/TargetOptions.h | 17 +-- llvm/include/llvm/TargetParser/Triple.h | 7 ++ llvm/lib/CodeGen/CommandFlags.cpp | 8 ++ .../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 63 +++++++++-- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 10 ++ .../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 6 +- .../MCTargetDesc/RISCVELFObjectWriter.cpp | 15 +++ .../RISCV/MCTargetDesc/RISCVFixupKinds.h | 6 ++ .../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 40 +++++++ .../Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp | 18 ++++ .../Target/RISCV/MCTargetDesc/RISCVMCExpr.h | 4 + llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 12 +++ .../Target/RISCV/RISCVExpandPseudoInsts.cpp | 51 +++++++++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 20 +++- llvm/lib/Target/RISCV/RISCVISelLowering.h | 1 + llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 6 +- llvm/lib/Target/RISCV/RISCVInstrInfo.td | 29 +++++ llvm/lib/Target/TargetMachine.cpp | 1 + llvm/test/CodeGen/RISCV/tls-models.ll | 102 ++++++++++++++++++ llvm/test/MC/RISCV/relocations.s | 21 ++++ llvm/test/MC/RISCV/tlsdesc.s | 44 ++++++++ 24 files changed, 473 insertions(+), 19 deletions(-) create mode 100644 llvm/test/MC/RISCV/tlsdesc.s diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def index b478799c91fb2f..d4be34e3b37e5e 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def @@ -15,6 +15,7 @@ ELF_RELOC(R_RISCV_TLS_DTPREL32, 8) ELF_RELOC(R_RISCV_TLS_DTPREL64, 9) ELF_RELOC(R_RISCV_TLS_TPREL32, 10) ELF_RELOC(R_RISCV_TLS_TPREL64, 11) +ELF_RELOC(R_RISCV_TLSDESC, 12) ELF_RELOC(R_RISCV_BRANCH, 16) ELF_RELOC(R_RISCV_JAL, 17) ELF_RELOC(R_RISCV_CALL, 18) @@ -56,3 +57,7 @@ ELF_RELOC(R_RISCV_IRELATIVE, 58) ELF_RELOC(R_RISCV_PLT32, 59) ELF_RELOC(R_RISCV_SET_ULEB128, 60) ELF_RELOC(R_RISCV_SUB_ULEB128, 61) +ELF_RELOC(R_RISCV_TLSDESC_HI20, 62) +ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 63) +ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 64) +ELF_RELOC(R_RISCV_TLSDESC_CALL, 65) diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h index 6407dde5bcd6c7..bf166a63edb071 100644 --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -117,6 +117,9 @@ unsigned getTLSSize(); bool getEmulatedTLS(); std::optional getExplicitEmulatedTLS(); +bool getEnableTLSDESC(); +std::optional getExplicitEnableTLSDESC(); + bool getUniqueSectionNames(); bool getUniqueBasicBlockSectionNames(); diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h index 1fe47dec70b163..a522a12299bb02 100644 --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -248,6 +248,9 @@ class TargetMachine { /// Returns true if this target uses emulated TLS. bool useEmulatedTLS() const; + /// Returns true if this target uses TLS Descriptors. + bool useTLSDESC() const; + /// Returns the TLS model which should be used for the given global variable. TLSModel::Model getTLSModel(const GlobalValue *GV) const; diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h index 4df897c047a38a..d02d1699813c94 100644 --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -145,13 +145,13 @@ namespace llvm { IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true), UniqueSectionNames(true), UniqueBasicBlockSectionNames(false), TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0), - EmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false), - EnableMachineOutliner(false), EnableMachineFunctionSplitter(false), - SupportsDefaultOutlining(false), EmitAddrsig(false), - EmitCallSiteInfo(false), SupportsDebugEntryValues(false), - EnableDebugEntryValues(false), ValueTrackingVariableLocations(false), - ForceDwarfFrameSection(false), XRayFunctionIndex(true), - DebugStrictDwarf(false), Hotpatch(false), + EmulatedTLS(false), EnableTLSDESC(false), EnableIPRA(false), + EmitStackSizeSection(false), EnableMachineOutliner(false), + EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false), + EmitAddrsig(false), EmitCallSiteInfo(false), + SupportsDebugEntryValues(false), EnableDebugEntryValues(false), + ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false), + XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false), EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false), FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {} @@ -295,6 +295,9 @@ namespace llvm { /// function in the runtime library.. unsigned EmulatedTLS : 1; + /// EnableTLSDESC - This flag enables TLS Descriptors. + unsigned EnableTLSDESC : 1; + /// This flag enables InterProcedural Register Allocation (IPRA). unsigned EnableIPRA : 1; diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 1f8c7a060e249d..870dc75b1c1f80 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -1033,6 +1033,13 @@ class Triple { isWindowsCygwinEnvironment() || isOHOSFamily(); } + /// Tests whether the target uses TLS Descriptor by default. + bool hasDefaultTLSDESC() const { + // TODO: Improve check for other platforms, like Android, and RISC-V + // Note: This is currently only used on RISC-V. + return isOSBinFormatELF() && isAArch64(); + } + /// Tests whether the target uses -data-sections as default. bool hasDefaultDataSections() const { return isOSBinFormatXCOFF() || isWasm(); diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp index c6d7827f36dfd6..51406fb287e665 100644 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -93,6 +93,7 @@ CGOPT(bool, XCOFFTracebackTable) CGOPT(std::string, BBSections) CGOPT(unsigned, TLSSize) CGOPT_EXP(bool, EmulatedTLS) +CGOPT_EXP(bool, EnableTLSDESC) CGOPT(bool, UniqueSectionNames) CGOPT(bool, UniqueBasicBlockSectionNames) CGOPT(EABI, EABIVersion) @@ -404,6 +405,11 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { "emulated-tls", cl::desc("Use emulated TLS model"), cl::init(false)); CGBINDOPT(EmulatedTLS); + static cl::opt EnableTLSDESC( + "enable-tlsdesc", cl::desc("Enable the use of TLS Descriptors"), + cl::init(false)); + CGBINDOPT(EnableTLSDESC); + static cl::opt UniqueSectionNames( "unique-section-names", cl::desc("Give unique names to every section"), cl::init(true)); @@ -568,6 +574,8 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) { Options.TLSSize = getTLSSize(); Options.EmulatedTLS = getExplicitEmulatedTLS().value_or(TheTriple.hasDefaultEmulatedTLS()); + Options.EnableTLSDESC = + getExplicitEnableTLSDESC().value_or(TheTriple.hasDefaultTLSDESC()); Options.ExceptionModel = getExceptionModel(); Options.EmitStackSizeSection = getEnableStackSizeSection(); Options.EnableMachineFunctionSplitter = getEnableMachineFunctionSplitter(); diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 7d42481db57fa9..f6e8386aff4510 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -169,6 +169,12 @@ class RISCVAsmParser : public MCTargetAsmParser { // 'add' is an overloaded mnemonic. bool checkPseudoAddTPRel(MCInst &Inst, OperandVector &Operands); + // Checks that a PseudoTLSDESCCall is using x5/t0 in its output operand. + // Enforcing this using a restricted register class for the output + // operand of PseudoTLSDESCCall results in a poor diagnostic due to the fact + // 'jalr' is an overloaded mnemonic. + bool checkPseudoTLSDESCCall(MCInst &Inst, OperandVector &Operands); + // Check instruction constraints. bool validateInstruction(MCInst &Inst, OperandVector &Operands); @@ -549,6 +555,16 @@ struct RISCVOperand final : public MCParsedAsmOperand { VK == RISCVMCExpr::VK_RISCV_TPREL_ADD; } + bool isTLSDESCCallSymbol() const { + int64_t Imm; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + // Must be of 'immediate' type but not a constant. + if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) + return false; + return RISCVAsmParser::classifySymbolRef(getImm(), VK) && + VK == RISCVMCExpr::VK_RISCV_TLSDESC_CALL; + } + bool isCSRSystemRegister() const { return isSystemRegister(); } bool isVTypeImm(unsigned N) const { @@ -601,7 +617,10 @@ struct RISCVOperand final : public MCParsedAsmOperand { if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); - if (VK == RISCVMCExpr::VK_RISCV_LO || VK == RISCVMCExpr::VK_RISCV_PCREL_LO) + if (VK == RISCVMCExpr::VK_RISCV_LO || + VK == RISCVMCExpr::VK_RISCV_PCREL_LO || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO) return true; // Given only Imm, ensuring that the actually specified constant is either // a signed or unsigned 64-bit number is unfortunately impossible. @@ -854,7 +873,9 @@ struct RISCVOperand final : public MCParsedAsmOperand { return IsValid && ((IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None) || VK == RISCVMCExpr::VK_RISCV_LO || VK == RISCVMCExpr::VK_RISCV_PCREL_LO || - VK == RISCVMCExpr::VK_RISCV_TPREL_LO); + VK == RISCVMCExpr::VK_RISCV_TPREL_LO || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO); } bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } @@ -911,14 +932,16 @@ struct RISCVOperand final : public MCParsedAsmOperand { return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI || VK == RISCVMCExpr::VK_RISCV_GOT_HI || VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI || - VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI); - } else { - return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || - VK == RISCVMCExpr::VK_RISCV_PCREL_HI || - VK == RISCVMCExpr::VK_RISCV_GOT_HI || - VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI || - VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI); + VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI); } + + return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || + VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI || + VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI || + VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI); } bool isSImm21Lsb0JAL() const { return isBareSimmNLsb0<21>(); } @@ -1556,6 +1579,11 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a symbol with %tprel_add modifier"); } + case Match_InvalidTLSDESCCallSymbol: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, + "operand must be a symbol with %tlsdesc_call modifier"); + } case Match_InvalidRTZArg: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be 'rtz' floating-point rounding mode"); @@ -3324,6 +3352,19 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst, return false; } +bool RISCVAsmParser::checkPseudoTLSDESCCall(MCInst &Inst, + OperandVector &Operands) { + assert(Inst.getOpcode() == RISCV::PseudoTLSDESCCall && "Invalid instruction"); + assert(Inst.getOperand(0).isReg() && "Unexpected operand kind"); + if (Inst.getOperand(0).getReg() != RISCV::X5) { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[3]).getStartLoc(); + return Error(ErrorLoc, "the output operand must be t0/x5 when using " + "%tlsdesc_call modifier"); + } + + return false; +} + std::unique_ptr RISCVAsmParser::defaultMaskRegOp() const { return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(), llvm::SMLoc()); @@ -3559,6 +3600,10 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (checkPseudoAddTPRel(Inst, Operands)) return true; break; + case RISCV::PseudoTLSDESCCall: + if (checkPseudoTLSDESCCall(Inst, Operands)) + return true; + break; case RISCV::PseudoSEXT_B: emitPseudoExtend(Inst, /*SignExtend=*/true, /*Width=*/8, IDLoc, Out); return false; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 7ce08eabdeb61d..bd49875c9591d0 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -86,6 +86,12 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, {"fixup_riscv_relax", 0, 0, 0}, {"fixup_riscv_align", 0, 0, 0}, + + {"fixup_riscv_tlsdesc_hi20", 12, 20, + MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget}, + {"fixup_riscv_tlsdesc_load_lo12", 20, 12, 0}, + {"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0}, + {"fixup_riscv_tlsdesc_call", 0, 0, 0}, }; static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); @@ -126,6 +132,7 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, case RISCV::fixup_riscv_got_hi20: case RISCV::fixup_riscv_tls_got_hi20: case RISCV::fixup_riscv_tls_gd_hi20: + case RISCV::fixup_riscv_tlsdesc_hi20: return true; } @@ -411,6 +418,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, case RISCV::fixup_riscv_got_hi20: case RISCV::fixup_riscv_tls_got_hi20: case RISCV::fixup_riscv_tls_gd_hi20: + case RISCV::fixup_riscv_tlsdesc_hi20: llvm_unreachable("Relocation should be unconditionally forced\n"); case FK_Data_1: case FK_Data_2: @@ -421,6 +429,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, case RISCV::fixup_riscv_lo12_i: case RISCV::fixup_riscv_pcrel_lo12_i: case RISCV::fixup_riscv_tprel_lo12_i: + case RISCV::fixup_riscv_tlsdesc_load_lo12: return Value & 0xfff; case RISCV::fixup_riscv_12_i: if (!isInt<12>(Value)) { @@ -524,6 +533,7 @@ bool RISCVAsmBackend::evaluateTargetFixup( switch (Fixup.getTargetKind()) { default: llvm_unreachable("Unexpected fixup kind!"); + case RISCV::fixup_riscv_tlsdesc_hi20: case RISCV::fixup_riscv_pcrel_hi20: AUIPCFixup = &Fixup; AUIPCDF = DF; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h index 433e2e6f80bd68..d7f7859ce4399b 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -264,11 +264,15 @@ enum { MO_TPREL_ADD = 10, MO_TLS_GOT_HI = 11, MO_TLS_GD_HI = 12, + MO_TLSDESC_HI = 13, + MO_TLSDESC_LOAD_LO = 14, + MO_TLSDESC_ADD_LO = 15, + MO_TLSDESC_CALL = 16, // Used to differentiate between target-specific "direct" flags and "bitmask" // flags. A machine operand can only have one "direct" flag, but can have // multiple "bitmask" flags. - MO_DIRECT_FLAG_MASK = 15 + MO_DIRECT_FLAG_MASK = 31 }; } // namespace RISCVII diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp index 76e5b3ed402543..2343c5fb2535a5 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 74bd9398a9ef6b..821372d3d39a63 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -71,6 +71,12 @@ enum Fixups { // Used to generate an R_RISCV_ALIGN relocation, which indicates the linker // should fixup the alignment after linker relaxation. fixup_riscv_align, + // Fixups indicating a TLS descriptor code sequence, corresponding to auipc, + // lw/ld, addi, and jalr, respectively. + fixup_riscv_tlsdesc_hi20, + fixup_riscv_tlsdesc_load_lo12, + fixup_riscv_tlsdesc_add_lo12, + fixup_riscv_tlsdesc_call, // Used as a sentinel, must be the last fixup_riscv_invalid, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp index 82fed50bce753a..5ea386c3c32a3d 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 &Fixups, const MCSubtargetInfo &STI) const; + void expandTLSDESCCall(const MCInst &MI, SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + void expandAddTPRel(const MCInst &MI, SmallVectorImpl &CB, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -154,6 +158,26 @@ void RISCVMCCodeEmitter::expandFunctionCall(const MCInst &MI, support::endian::write(CB, Binary, llvm::endianness::little); } +void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI, + SmallVectorImpl &CB, + SmallVectorImpl &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(SrcSymbol.getExpr()); + MCRegister Link = MI.getOperand(0).getReg(); + MCRegister Dest = MI.getOperand(1).getReg(); + MCRegister Imm = MI.getOperand(2).getImm(); + Fixups.push_back(MCFixup::create( + 0, Expr, MCFixupKind(RISCV::fixup_riscv_tlsdesc_call), MI.getLoc())); + MCInst Call = + MCInstBuilder(RISCV::JALR).addReg(Link).addReg(Dest).addImm(Imm); + + uint32_t Binary = getBinaryCodeForInstr(Call, Fixups, STI); + support::endian::write(CB, Binary, llvm::endianness::little); +} + // Expand PseudoAddTPRel to a simple ADD with the correct relocation. void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, SmallVectorImpl &CB, @@ -303,6 +327,10 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, expandLongCondBr(MI, CB, Fixups, STI); MCNumEmitted += 2; return; + case RISCV::PseudoTLSDESCCall: + expandTLSDESCCall(MI, CB, Fixups, STI); + MCNumEmitted += 1; + return; } switch (Size) { @@ -445,6 +473,18 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, FixupKind = RISCV::fixup_riscv_call_plt; RelaxCandidate = true; break; + case RISCVMCExpr::VK_RISCV_TLSDESC_HI: + FixupKind = RISCV::fixup_riscv_tlsdesc_hi20; + break; + case RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO: + FixupKind = RISCV::fixup_riscv_tlsdesc_load_lo12; + break; + case RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO: + FixupKind = RISCV::fixup_riscv_tlsdesc_add_lo12; + break; + case RISCVMCExpr::VK_RISCV_TLSDESC_CALL: + FixupKind = RISCV::fixup_riscv_tlsdesc_call; + break; } } else if ((Kind == MCExpr::SymbolRef && cast(Expr)->getKind() == diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp index 64ddae61b1bc15..254a9a4bc0ef0b 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -79,6 +79,7 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const { case RISCV::fixup_riscv_tls_got_hi20: case RISCV::fixup_riscv_tls_gd_hi20: case RISCV::fixup_riscv_pcrel_hi20: + case RISCV::fixup_riscv_tlsdesc_hi20: if (DFOut) *DFOut = DF; return &F; @@ -119,6 +120,10 @@ RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { .Case("tprel_add", VK_RISCV_TPREL_ADD) .Case("tls_ie_pcrel_hi", VK_RISCV_TLS_GOT_HI) .Case("tls_gd_pcrel_hi", VK_RISCV_TLS_GD_HI) + .Case("tlsdesc_hi", VK_RISCV_TLSDESC_HI) + .Case("tlsdesc_load_lo", VK_RISCV_TLSDESC_LOAD_LO) + .Case("tlsdesc_add_lo", VK_RISCV_TLSDESC_ADD_LO) + .Case("tlsdesc_call", VK_RISCV_TLSDESC_CALL) .Default(VK_RISCV_Invalid); } @@ -145,6 +150,14 @@ StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { return "tprel_add"; case VK_RISCV_TLS_GOT_HI: return "tls_ie_pcrel_hi"; + case VK_RISCV_TLSDESC_HI: + return "tlsdesc_hi"; + case VK_RISCV_TLSDESC_LOAD_LO: + return "tlsdesc_load_lo"; + case VK_RISCV_TLSDESC_ADD_LO: + return "tlsdesc_add_lo"; + case VK_RISCV_TLSDESC_CALL: + return "tlsdesc_call"; case VK_RISCV_TLS_GD_HI: return "tls_gd_pcrel_hi"; case VK_RISCV_CALL: @@ -193,6 +206,9 @@ void RISCVMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { case VK_RISCV_TPREL_HI: case VK_RISCV_TLS_GOT_HI: case VK_RISCV_TLS_GD_HI: + case VK_RISCV_TLSDESC_HI: + case VK_RISCV_TLSDESC_ADD_LO: + case VK_RISCV_TLSDESC_LOAD_LO: break; } @@ -206,6 +222,8 @@ bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_TPREL_HI || Kind == VK_RISCV_TPREL_LO || Kind == VK_RISCV_TPREL_ADD || Kind == VK_RISCV_TLS_GOT_HI || Kind == VK_RISCV_TLS_GD_HI || + Kind == VK_RISCV_TLSDESC_HI || Kind == VK_RISCV_TLSDESC_LOAD_LO || + Kind == VK_RISCV_TLSDESC_ADD_LO || Kind == VK_RISCV_TLSDESC_CALL || Kind == VK_RISCV_CALL || Kind == VK_RISCV_CALL_PLT) return false; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h index 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 aee6ec05f1f9c5..b2e9cd87373b0f 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -780,6 +780,18 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, case RISCVII::MO_TLS_GD_HI: Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI; break; + case RISCVII::MO_TLSDESC_HI: + Kind = RISCVMCExpr::VK_RISCV_TLSDESC_HI; + break; + case RISCVII::MO_TLSDESC_LOAD_LO: + Kind = RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO; + break; + case RISCVII::MO_TLSDESC_ADD_LO: + Kind = RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO; + break; + case RISCVII::MO_TLSDESC_CALL: + Kind = RISCVMCExpr::VK_RISCV_TLSDESC_CALL; + break; } const MCExpr *ME = diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index ed2b1ceb7d6f0d..0a314fdd41cbe2 100644 --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -423,6 +423,10 @@ class RISCVPreRAExpandPseudo : public MachineFunctionPass { bool expandLoadTLSGDAddress(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); + bool expandLoadTLSDescAddress(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + #ifndef NDEBUG unsigned getInstSizeInBytes(const MachineFunction &MF) const { unsigned Size = 0; @@ -481,6 +485,8 @@ bool RISCVPreRAExpandPseudo::expandMI(MachineBasicBlock &MBB, return expandLoadTLSIEAddress(MBB, MBBI, NextMBBI); case RISCV::PseudoLA_TLS_GD: return expandLoadTLSGDAddress(MBB, MBBI, NextMBBI); + case RISCV::PseudoLA_TLSDESC: + return expandLoadTLSDescAddress(MBB, MBBI, NextMBBI); } return false; } @@ -547,6 +553,51 @@ bool RISCVPreRAExpandPseudo::expandLoadTLSGDAddress( RISCV::ADDI); } +bool RISCVPreRAExpandPseudo::expandLoadTLSDescAddress( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + MachineFunction *MF = MBB.getParent(); + MachineInstr &MI = *MBBI; + DebugLoc DL = MI.getDebugLoc(); + + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? RISCV::LD : RISCV::LW; + + Register FinalReg = MI.getOperand(0).getReg(); + Register DestReg = + MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); + Register ScratchReg = + MF->getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); + + MachineOperand &Symbol = MI.getOperand(1); + Symbol.setTargetFlags(RISCVII::MO_TLSDESC_HI); + MCSymbol *AUIPCSymbol = MF->getContext().createNamedTempSymbol("tlsdesc_hi"); + + MachineInstr *MIAUIPC = + BuildMI(MBB, MBBI, DL, TII->get(RISCV::AUIPC), ScratchReg).add(Symbol); + MIAUIPC->setPreInstrSymbol(*MF, AUIPCSymbol); + + BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) + .addReg(ScratchReg) + .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_LOAD_LO); + + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), RISCV::X10) + .addReg(ScratchReg) + .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_ADD_LO); + + BuildMI(MBB, MBBI, DL, TII->get(RISCV::PseudoTLSDESCCall), RISCV::X5) + .addReg(DestReg) + .addImm(0) + .addSym(AUIPCSymbol, RISCVII::MO_TLSDESC_CALL); + + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADD), FinalReg) + .addReg(RISCV::X10) + .addReg(RISCV::X4); + + MI.eraseFromParent(); + return true; +} + } // end of anonymous namespace INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo", diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index e39888637062c6..47c6cd6e5487b8 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -6982,6 +6982,23 @@ SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, return LowerCallTo(CLI).first; } +SDValue RISCVTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + const GlobalValue *GV = N->getGlobal(); + + // Use a PC-relative addressing mode to access the global dynamic GOT address. + // This generates the pattern (PseudoLA_TLSDESC sym), which expands to + // + // auipc tX, %tlsdesc_hi(symbol) // R_RISCV_TLSDESC_HI20(symbol) + // lw tY, tX, %tlsdesc_lo_load(label) // R_RISCV_TLSDESC_LOAD_LO12_I(label) + // addi a0, tX, %tlsdesc_lo_add(label) // R_RISCV_TLSDESC_ADD_LO12_I(label) + // jalr t0, tY // R_RISCV_TLSDESC_CALL(label) + SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); + return SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLSDESC, DL, Ty, Addr), 0); +} + SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { GlobalAddressSDNode *N = cast(Op); @@ -7006,7 +7023,8 @@ SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, break; case TLSModel::LocalDynamic: case TLSModel::GeneralDynamic: - Addr = getDynamicTLSAddr(N, DAG); + Addr = DAG.getTarget().useTLSDESC() ? getTLSDescAddr(N, DAG) + : getDynamicTLSAddr(N, DAG); break; } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index a55a6046166719..30b9ad7e6f6f32 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -855,6 +855,7 @@ class RISCVTargetLowering : public TargetLowering { SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, bool UseGOT) const; SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const; + SDValue getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const; SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 7c21f635849428..592962cebe8973 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -2379,7 +2379,11 @@ RISCVInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { {MO_TPREL_HI, "riscv-tprel-hi"}, {MO_TPREL_ADD, "riscv-tprel-add"}, {MO_TLS_GOT_HI, "riscv-tls-got-hi"}, - {MO_TLS_GD_HI, "riscv-tls-gd-hi"}}; + {MO_TLS_GD_HI, "riscv-tls-gd-hi"}, + {MO_TLSDESC_HI, "riscv-tlsdesc-hi"}, + {MO_TLSDESC_LOAD_LO, "riscv-tlsdesc-load-lo"}, + {MO_TLSDESC_ADD_LO, "riscv-tlsdesc-add-lo"}, + {MO_TLSDESC_CALL, "riscv-tlsdesc-call"}}; return ArrayRef(TargetFlags); } bool RISCVInstrInfo::isFunctionSafeToOutlineFrom( diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index 792e0bbdf5816c..114329c2c7c5f3 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1742,6 +1742,35 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0, def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], "la.tls.gd", "$dst, $src">; +let hasSideEffects = 0, mayLoad = 1, mayStore = 0, Size = 32, isCodeGenOnly = 0 in +def PseudoLA_TLSDESC : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [], + "la.tlsdesc", "$dst, $src">; + +def TLSDESCCallSymbol : AsmOperandClass { + let Name = "TLSDESCCallSymbol"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidTLSDESCCallSymbol"; + let ParserMethod = "parseOperandWithModifier"; +} + +// A bare symbol with the %tlsdesc_call variant. +def tlsdesc_call_symbol : Operand { + let ParserMatchClass = TLSDESCCallSymbol; +} +// This is a special case of the JALR instruction used to facilitate the use of a +// fourth operand to emit a relocation on a symbol relating to this instruction. +// The relocation does not affect any bits of the instruction itself but is used +// as a hint to the linker. +let isCall = 1, isBarrier = 1, isCodeGenOnly = 0, Size = 8, hasSideEffects = 0, + mayStore = 0, mayLoad = 0 in +def PseudoTLSDESCCall : Pseudo<(outs GPR:$rd), + (ins GPR:$rs1, simm12:$imm12, tlsdesc_call_symbol:$src), [], + "jalr", "$rd, ${imm12}(${rs1}), $src">, + Sched<[WriteJalr, ReadJalr]> { + let Defs = [X10]; + let Uses = [X10]; +} + /// Sign/Zero Extends diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index abd0fdf2390c04..0839fb22d35a8f 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -213,6 +213,7 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M, } bool TargetMachine::useEmulatedTLS() const { return Options.EmulatedTLS; } +bool TargetMachine::useTLSDESC() const { return Options.EnableTLSDESC; } TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const { bool IsPIE = GV->getParent()->getPIELevel() != PIELevel::Default; diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll index c2ed44073baac1..b99896e3501911 100644 --- a/llvm/test/CodeGen/RISCV/tls-models.ll +++ b/llvm/test/CodeGen/RISCV/tls-models.ll @@ -1,10 +1,16 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s \ ; RUN: | FileCheck -check-prefix=RV32-PIC %s +; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s -enable-tlsdesc \ +; RUN: | FileCheck -check-prefix=RV32-PIC-TLSDESC %s ; RUN: llc -mtriple=riscv64 -relocation-model=pic < %s \ ; RUN: | FileCheck -check-prefix=RV64-PIC %s +; RUN: llc -mtriple=riscv64 -relocation-model=pic -enable-tlsdesc < %s \ +; RUN: | FileCheck -check-prefix=RV64-PIC-TLSDESC %s ; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32-NOPIC %s +; RUN: llc -mtriple=riscv32 < %s -enable-tlsdesc | FileCheck -check-prefix=RV32-NOPIC-TLSDESC %s ; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64-NOPIC %s +; RUN: llc -mtriple=riscv64 < %s -enable-tlsdesc | FileCheck -check-prefix=RV64-NOPIC-TLSDESC %s ; Check that TLS symbols are lowered correctly based on the specified ; model. Make sure they're external to avoid them all being optimised to Local @@ -58,6 +64,42 @@ define ptr @f1() nounwind { ; RV64-NOPIC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) ; RV64-NOPIC-NEXT: add a0, a0, tp ; RV64-NOPIC-NEXT: ret +; +; RV32-PIC-TLSDESC-LABEL: f1: +; RV32-PIC-TLSDESC: # %bb.0: # %entry +; RV32-PIC-TLSDESC-NEXT: .Ltlsdesc_hi0: +; RV32-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(unspecified) +; RV32-PIC-TLSDESC-NEXT: lw a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0) +; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0) +; RV32-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0) +; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-PIC-TLSDESC-NEXT: ret +; +; RV64-PIC-TLSDESC-LABEL: f1: +; RV64-PIC-TLSDESC: # %bb.0: # %entry +; RV64-PIC-TLSDESC-NEXT: .Ltlsdesc_hi0: +; RV64-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(unspecified) +; RV64-PIC-TLSDESC-NEXT: ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0) +; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0) +; RV64-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0) +; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-PIC-TLSDESC-NEXT: ret +; +; RV32-NOPIC-TLSDESC-LABEL: f1: +; RV32-NOPIC-TLSDESC: # %bb.0: # %entry +; RV32-NOPIC-TLSDESC-NEXT: .Lpcrel_hi0: +; RV32-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(unspecified) +; RV32-NOPIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-TLSDESC-LABEL: f1: +; RV64-NOPIC-TLSDESC: # %bb.0: # %entry +; RV64-NOPIC-TLSDESC-NEXT: .Lpcrel_hi0: +; RV64-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(unspecified) +; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-NOPIC-TLSDESC-NEXT: ret entry: ret ptr @unspecified } @@ -144,6 +186,38 @@ define ptr @f3() nounwind { ; RV64-NOPIC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0) ; RV64-NOPIC-NEXT: add a0, a0, tp ; RV64-NOPIC-NEXT: ret +; +; RV32-PIC-TLSDESC-LABEL: f3: +; RV32-PIC-TLSDESC: # %bb.0: # %entry +; RV32-PIC-TLSDESC-NEXT: .Lpcrel_hi0: +; RV32-PIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV32-PIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-PIC-TLSDESC-NEXT: ret +; +; RV64-PIC-TLSDESC-LABEL: f3: +; RV64-PIC-TLSDESC: # %bb.0: # %entry +; RV64-PIC-TLSDESC-NEXT: .Lpcrel_hi0: +; RV64-PIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV64-PIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-PIC-TLSDESC-NEXT: ret +; +; RV32-NOPIC-TLSDESC-LABEL: f3: +; RV32-NOPIC-TLSDESC: # %bb.0: # %entry +; RV32-NOPIC-TLSDESC-NEXT: .Lpcrel_hi2: +; RV32-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV32-NOPIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi2)(a0) +; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-TLSDESC-LABEL: f3: +; RV64-NOPIC-TLSDESC: # %bb.0: # %entry +; RV64-NOPIC-TLSDESC-NEXT: .Lpcrel_hi2: +; RV64-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0) +; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-NOPIC-TLSDESC-NEXT: ret entry: ret ptr @ie } @@ -179,6 +253,34 @@ define ptr @f4() nounwind { ; RV64-NOPIC-NEXT: add a0, a0, tp, %tprel_add(le) ; RV64-NOPIC-NEXT: addi a0, a0, %tprel_lo(le) ; RV64-NOPIC-NEXT: ret +; +; RV32-PIC-TLSDESC-LABEL: f4: +; RV32-PIC-TLSDESC: # %bb.0: # %entry +; RV32-PIC-TLSDESC-NEXT: lui a0, %tprel_hi(le) +; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le) +; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) +; RV32-PIC-TLSDESC-NEXT: ret +; +; RV64-PIC-TLSDESC-LABEL: f4: +; RV64-PIC-TLSDESC: # %bb.0: # %entry +; RV64-PIC-TLSDESC-NEXT: lui a0, %tprel_hi(le) +; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le) +; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) +; RV64-PIC-TLSDESC-NEXT: ret +; +; RV32-NOPIC-TLSDESC-LABEL: f4: +; RV32-NOPIC-TLSDESC: # %bb.0: # %entry +; RV32-NOPIC-TLSDESC-NEXT: lui a0, %tprel_hi(le) +; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le) +; RV32-NOPIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) +; RV32-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-TLSDESC-LABEL: f4: +; RV64-NOPIC-TLSDESC: # %bb.0: # %entry +; RV64-NOPIC-TLSDESC-NEXT: lui a0, %tprel_hi(le) +; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le) +; RV64-NOPIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) +; RV64-NOPIC-TLSDESC-NEXT: ret entry: ret ptr @le } diff --git a/llvm/test/MC/RISCV/relocations.s b/llvm/test/MC/RISCV/relocations.s index 262b3e44c6f007..d9d941697704c2 100644 --- a/llvm/test/MC/RISCV/relocations.s +++ b/llvm/test/MC/RISCV/relocations.s @@ -176,3 +176,24 @@ bgeu a0, a1, foo # RELOC: R_RISCV_JAL # INSTR: bgeu a0, a1, foo # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch + +.L5: +auipc a0, %tlsdesc_hi(a_symbol) +# RELOC: R_RISCV_TLSDESC_HI20 +# INST: auipc a0, 0x0 +# FIXUP: fixup A - offset: 0, value: %tlsdesc_hi(a_symbol), kind: fixup_riscv_tlsdesc_hi20 + +lw a1, %tlsdesc_load_lo(.L5)(a0) +# RELOC: R_RISCV_TLSDESC_LOAD_LO12 +# INST: lw a1, 0x0(a0) +# FIXUP: fixup A - offset: 0, value: %tlsdesc_load_lo(.L5), kind: fixup_riscv_tlsdesc_load_lo12 + +addi a0, a0, %tlsdesc_add_lo(.L5) +# RELOC: R_RISCV_TLSDESC_ADD_LO12 +# INST: addi a0, a0, 0x0 +# FIXUP: fixup A - offset: 0, value: %tlsdesc_add_lo(.L5), kind: fixup_riscv_tlsdesc_add_lo12 + +jalr t0, 0(a1), %tlsdesc_call(.L5) +# RELOC: R_RISCV_TLSDESC_CALL +# INST: jalr t0, 0x0(a1) +# FIXUP: fixup A - offset: 0, value: %tlsdesc_call(.L5), kind: fixup_riscv_tlsdesc_call diff --git a/llvm/test/MC/RISCV/tlsdesc.s b/llvm/test/MC/RISCV/tlsdesc.s new file mode 100644 index 00000000000000..f455e266ab1557 --- /dev/null +++ b/llvm/test/MC/RISCV/tlsdesc.s @@ -0,0 +1,44 @@ +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s --defsym RV32=1 | llvm-objdump -d -M no-aliases - | FileCheck %s --check-prefixes=INST,RV32 +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s | llvm-objdump -d -M no-aliases - | FileCheck %s --check-prefixes=INST,RV64 + +# RUN: not llvm-mc -triple riscv32 < %s --defsym RV32=1 --defsym ERR=1 2>&1 | FileCheck %s --check-prefixes=ERR +# RUN: not llvm-mc -triple riscv64 < %s --defsym ERR=1 2>&1 | FileCheck %s --check-prefixes=ERR + +start: # @start +# %bb.0: # %entry +.Ltlsdesc_hi0: + auipc a0, %tlsdesc_hi(a-4) + # INST: auipc a0, 0x0 + auipc a0, %tlsdesc_hi(unspecified) + # INST: auipc a0, 0x0 +.ifdef RV32 + lw a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0) + # RV32: lw a1, 0x0(a0) +.else + ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0) + #RV64: ld a1, 0x0(a0) +.endif + addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0) + # INST: addi a0, a0, 0x0 + jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0) + # INST: jalr t0, 0x0(a1) + add a0, a0, tp + # INST: add a0, a0, tp + ret + +## Check invalid usage +.ifdef ERR + auipc x1, %tlsdesc_call(foo) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range + auipc x1, %tlsdesc_call(1234) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range + auipc a0, %tlsdesc_hi(a+b) # ERR: :[[#@LINE]]:12: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi modifier or an integer in the range + + lw a0, t0, %tlsdesc_load_lo(a_symbol) # ERR: :[[#@LINE]]:15: error: invalid operand for instruction + lw a0, t0, %tlsdesc_load_lo(a_symbol)(a4) # ERR: :[[#@LINE]]:15: error: invalid operand for instruction + + addi a0, t0, %tlsdesc_add_lo(a_symbol)(a4) # ERR: :[[#@LINE]]:41: error: invalid operand for instruction + addi a0, %tlsdesc_add_lo(a_symbol) # ERR: :[[#@LINE]]:11: error: invalid operand for instruction + addi x1, %tlsdesc_load_lo(a_symbol)(a0) # ERR: :[[#@LINE]]:11: error: invalid operand for instruction + + jalr x5, 0(a1), %tlsdesc_hi(a_symbol) # ERR: :[[#@LINE]]:18: error: operand must be a symbol with %tlsdesc_call modifier + jalr x1, 0(a1), %tlsdesc_call(a_symbol) # ERR: :[[#@LINE]]:13: error: the output operand must be t0/x5 when using %tlsdesc_call modifier +.endif