diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def @@ -55,3 +55,8 @@ 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, 60) +ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 61) +ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 62) +ELF_RELOC(R_RISCV_TLSDESC_CALL, 63) +ELF_RELOC(R_RISCV_TLSDESC, 64) diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -149,6 +149,7 @@ // 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, @@ -167,6 +168,12 @@ // '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); @@ -525,6 +532,16 @@ 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 { @@ -874,14 +891,16 @@ 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>(); } @@ -1482,6 +1501,11 @@ 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"); @@ -3017,6 +3041,41 @@ 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) { @@ -3156,6 +3215,18 @@ 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(), @@ -3322,6 +3393,9 @@ 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 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -94,6 +94,11 @@ {"fixup_riscv_set_6b", 2, 6, 0}, {"fixup_riscv_sub_6b", 2, 6, 0}, + + {"fixup_riscv_tlsdesc_hi20", 12, 20, 0}, + {"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"); @@ -132,6 +137,7 @@ 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; } @@ -398,6 +404,7 @@ 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 RISCV::fixup_riscv_set_8: case RISCV::fixup_riscv_add_8: @@ -421,6 +428,7 @@ 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)) { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -219,11 +219,15 @@ 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 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -77,6 +77,14 @@ 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: @@ -112,6 +120,15 @@ default: Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); return ELF::R_RISCV_NONE; + 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 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 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -106,6 +106,18 @@ // 6-bit fixup corresponding to R_RISCV_SUB6 for local label assignment in // DWARF CFA. fixup_riscv_sub_6b, + // 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 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -57,6 +57,10 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + void expandTLSDESCCall(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + void expandAddTPRel(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -149,6 +153,31 @@ support::endian::write(OS, Binary, support::little); } +void RISCVMCCodeEmitter::expandTLSDESCCall(const MCInst &MI, raw_ostream &OS, + 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())); + // 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(OS, Binary, support::little); +} + // Expand PseudoAddTPRel to a simple ADD with the correct relocation. void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, @@ -295,6 +324,10 @@ expandLongCondBr(MI, OS, Fixups, STI); MCNumEmitted += 2; return; + case RISCV::PseudoTLSDESCCall: + expandTLSDESCCall(MI, OS, Fixups, STI); + MCNumEmitted += 1; + return; } switch (Size) { @@ -437,6 +470,19 @@ 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(Expr)->getKind() == MCSymbolRefExpr::VK_None) { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -37,6 +37,10 @@ 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/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -81,6 +81,7 @@ 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 @@ .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 @@ 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 @@ 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 @@ 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/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -290,6 +290,10 @@ 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; @@ -347,6 +351,8 @@ 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; } @@ -424,6 +430,53 @@ 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); + + 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.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -56,6 +56,7 @@ // Load address. LA_TLS_GD, + LA_TLSDESC, // Multiply high for signedxunsigned. MULHSU, @@ -760,6 +761,10 @@ SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, bool UseGOT) const; SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const; + SDValue getGeneralDynamicTLSDescAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG) const; + SDValue getLocalDynamicTLSDescAddr(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/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -49,6 +49,8 @@ STATISTIC(NumTailCalls, "Number of tail calls"); +extern cl::opt EnableRISCVTLSDESC; + static cl::opt ExtensionMaxWebSize( DEBUG_TYPE "-ext-max-web-size", cl::Hidden, cl::desc("Give the maximum size (in number of nodes) of the web of " @@ -5310,6 +5312,60 @@ 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::getLocalDynamicTLSDescAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG) const { + // Local-dynamic accesses proceed in two phases. A general-dynamic TLS + // descriptor call against the special symbol _TLS_MODULE_BASE_ to calculate + // the beginning of the module's TLS region, followed by a DTPREL offset + // calculation. + + SDValue TPOff; + EVT Ty = getPointerTy(DAG.getDataLayout()); + const GlobalValue *GV = N->getGlobal(); + SDLoc DL(N); + + // These accesses will need deduplicating if there's more than one. + RISCVMachineFunctionInfo *MFI = + DAG.getMachineFunction().getInfo(); + MFI->incNumLocalDynamicTLSAccesses(); + + // The call needs a relocation too for linker relaxation. + SDValue SymAddr = + DAG.getTargetExternalSymbol("_TLS_MODULE_BASE_", Ty, RISCVII::MO_GOT_HI); + + // Now we can calculate the offset from TP to this module's thread-local area. + TPOff = DAG.getNode(RISCVISD::LA_TLSDESC, DL, Ty, SymAddr); + + // Generate a sequence for accessing the address relative to the TLS module + SDValue AddrHi = + DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_HI); + SDValue AddrLo = + DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_LO); + + SDValue MNHi = DAG.getNode(RISCVISD::HI, DL, Ty, AddrHi); + SDValue MNAdd = DAG.getNode(ISD::ADD, DL, Ty, MNHi, TPOff); + return DAG.getNode(RISCVISD::ADD_LO, DL, Ty, MNAdd, AddrLo); +} + SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { GlobalAddressSDNode *N = cast(Op); @@ -5333,8 +5389,12 @@ Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/true); break; case TLSModel::LocalDynamic: + Addr = EnableRISCVTLSDESC ? getLocalDynamicTLSDescAddr(N, DAG) + : getDynamicTLSAddr(N, DAG); + break; case TLSModel::GeneralDynamic: - Addr = getDynamicTLSAddr(N, DAG); + Addr = EnableRISCVTLSDESC ? getGeneralDynamicTLSDescAddr(N, DAG) + : getDynamicTLSAddr(N, DAG); break; } @@ -15057,6 +15117,7 @@ NODE_NAME_CASE(LA) 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/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1923,7 +1923,11 @@ {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 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -95,6 +95,7 @@ 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. @@ -1618,10 +1619,45 @@ 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 { + 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/RISCVMCInstLower.cpp b/llvm/lib/Target/RISCV/RISCVMCInstLower.cpp --- a/llvm/lib/Target/RISCV/RISCVMCInstLower.cpp +++ b/llvm/lib/Target/RISCV/RISCVMCInstLower.cpp @@ -73,6 +73,18 @@ 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/RISCVMachineFunctionInfo.h b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h --- a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h +++ b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h @@ -65,6 +65,9 @@ uint64_t RVVPadding = 0; /// Size of stack frame to save callee saved registers unsigned CalleeSavedStackSize = 0; + /// Number of TLS accesses using the special (combinable) + /// _TLS_MODULE_BASE_ symbol. + unsigned NumLocalDynamicTLSAccesses = 0; /// Is there any vector argument or return? bool IsVectorCall = false; @@ -129,6 +132,11 @@ bool isVectorCall() const { return IsVectorCall; } void setIsVectorCall() { IsVectorCall = true; } + + void incNumLocalDynamicTLSAccesses() { ++NumLocalDynamicTLSAccesses; } + unsigned getNumLocalDynamicTLSAccesses() const { + return NumLocalDynamicTLSAccesses; + } }; } // end namespace llvm diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -71,6 +71,10 @@ cl::desc("Enable the copy propagation with RISC-V copy instr"), cl::init(true), cl::Hidden); +cl::opt EnableRISCVTLSDESC("riscv-enable-tlsdesc", + cl::desc("Enable the tlsdesc for RISC-V"), + cl::Hidden); + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() { RegisterTargetMachine X(getTheRISCV32Target()); RegisterTargetMachine Y(getTheRISCV64Target()); diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll --- a/llvm/test/CodeGen/RISCV/tls-models.ll +++ b/llvm/test/CodeGen/RISCV/tls-models.ll @@ -6,6 +6,14 @@ ; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32-NOPIC %s ; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64-NOPIC %s +; RUN: llc -mtriple=riscv32 -relocation-model=pic -riscv-enable-tlsdesc < %s \ +; RUN: | FileCheck -check-prefix=RV32-PIC-TLSDESC %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 -riscv-enable-tlsdesc | FileCheck -check-prefix=RV32-NOPIC-TLSDESC %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 ; Exec for the executable. @@ -58,6 +66,42 @@ ; 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 } @@ -105,6 +149,48 @@ ; RV64-NOPIC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi1)(a0) ; RV64-NOPIC-NEXT: add a0, a0, tp ; RV64-NOPIC-NEXT: ret +; +; RV32-PIC-TLSDESC-LABEL: f2: +; RV32-PIC-TLSDESC: # %bb.0: # %entry +; RV32-PIC-TLSDESC-NEXT: .Ltlsdesc_hi1: +; RV32-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(_TLS_MODULE_BASE_) +; RV32-PIC-TLSDESC-NEXT: lw a1, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a0) +; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi1) +; RV32-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi1) +; RV32-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-PIC-TLSDESC-NEXT: lui a1, %tprel_hi(ld) +; RV32-PIC-TLSDESC-NEXT: add a0, a1, a0 +; RV32-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(ld) +; RV32-PIC-TLSDESC-NEXT: ret +; +; RV64-PIC-TLSDESC-LABEL: f2: +; RV64-PIC-TLSDESC: # %bb.0: # %entry +; RV64-PIC-TLSDESC-NEXT: .Ltlsdesc_hi1: +; RV64-PIC-TLSDESC-NEXT: auipc a0, %tlsdesc_hi(_TLS_MODULE_BASE_) +; RV64-PIC-TLSDESC-NEXT: ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a0) +; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi1) +; RV64-PIC-TLSDESC-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi1) +; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-PIC-TLSDESC-NEXT: lui a1, %tprel_hi(ld) +; RV64-PIC-TLSDESC-NEXT: add a0, a1, a0 +; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(ld) +; RV64-PIC-TLSDESC-NEXT: ret +; +; RV32-NOPIC-TLSDESC-LABEL: f2: +; RV32-NOPIC-TLSDESC: # %bb.0: # %entry +; RV32-NOPIC-TLSDESC-NEXT: .Lpcrel_hi1: +; RV32-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ld) +; RV32-NOPIC-TLSDESC-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi1)(a0) +; RV32-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV32-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-TLSDESC-LABEL: f2: +; RV64-NOPIC-TLSDESC: # %bb.0: # %entry +; RV64-NOPIC-TLSDESC-NEXT: .Lpcrel_hi1: +; RV64-NOPIC-TLSDESC-NEXT: auipc a0, %tls_ie_pcrel_hi(ld) +; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi1)(a0) +; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp +; RV64-NOPIC-TLSDESC-NEXT: ret entry: ret ptr @ld } @@ -144,6 +230,38 @@ ; 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 +297,34 @@ ; 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 }