Skip to content

Commit 03a61d3

Browse files
authored
[RISCV] Support TLSDESC in the RISC-V backend (#66915)
This patch adds basic TLSDESC support in the RISC-V backend. Specifically, we add new relocation types for TLSDESC, as prescribed in riscv-non-isa/riscv-elf-psabi-doc#373, and add a new pseudo instruction to simplify code generation. This patch does not try to optimize the local dynamic case, which can be improved in separate patches. Linker side changes will also be handled separately. The current implementation is only enabled when passing the new `-enable-tlsdesc` codegen flag.
1 parent d657519 commit 03a61d3

24 files changed

+479
-19
lines changed

llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ ELF_RELOC(R_RISCV_TLS_DTPREL32, 8)
1515
ELF_RELOC(R_RISCV_TLS_DTPREL64, 9)
1616
ELF_RELOC(R_RISCV_TLS_TPREL32, 10)
1717
ELF_RELOC(R_RISCV_TLS_TPREL64, 11)
18+
ELF_RELOC(R_RISCV_TLSDESC, 12)
1819
ELF_RELOC(R_RISCV_BRANCH, 16)
1920
ELF_RELOC(R_RISCV_JAL, 17)
2021
ELF_RELOC(R_RISCV_CALL, 18)
@@ -56,3 +57,7 @@ ELF_RELOC(R_RISCV_IRELATIVE, 58)
5657
ELF_RELOC(R_RISCV_PLT32, 59)
5758
ELF_RELOC(R_RISCV_SET_ULEB128, 60)
5859
ELF_RELOC(R_RISCV_SUB_ULEB128, 61)
60+
ELF_RELOC(R_RISCV_TLSDESC_HI20, 62)
61+
ELF_RELOC(R_RISCV_TLSDESC_LOAD_LO12, 63)
62+
ELF_RELOC(R_RISCV_TLSDESC_ADD_LO12, 64)
63+
ELF_RELOC(R_RISCV_TLSDESC_CALL, 65)

llvm/include/llvm/CodeGen/CommandFlags.h

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ unsigned getTLSSize();
117117
bool getEmulatedTLS();
118118
std::optional<bool> getExplicitEmulatedTLS();
119119

120+
bool getEnableTLSDESC();
121+
std::optional<bool> getExplicitEnableTLSDESC();
122+
120123
bool getUniqueSectionNames();
121124

122125
bool getUniqueBasicBlockSectionNames();

llvm/include/llvm/Target/TargetMachine.h

+3
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ class TargetMachine {
248248
/// Returns true if this target uses emulated TLS.
249249
bool useEmulatedTLS() const;
250250

251+
/// Returns true if this target uses TLS Descriptors.
252+
bool useTLSDESC() const;
253+
251254
/// Returns the TLS model which should be used for the given global variable.
252255
TLSModel::Model getTLSModel(const GlobalValue *GV) const;
253256

llvm/include/llvm/Target/TargetOptions.h

+10-7
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,13 @@ namespace llvm {
145145
IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
146146
UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
147147
TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
148-
EmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false),
149-
EnableMachineOutliner(false), EnableMachineFunctionSplitter(false),
150-
SupportsDefaultOutlining(false), EmitAddrsig(false),
151-
EmitCallSiteInfo(false), SupportsDebugEntryValues(false),
152-
EnableDebugEntryValues(false), ValueTrackingVariableLocations(false),
153-
ForceDwarfFrameSection(false), XRayFunctionIndex(true),
154-
DebugStrictDwarf(false), Hotpatch(false),
148+
EmulatedTLS(false), EnableTLSDESC(false), EnableIPRA(false),
149+
EmitStackSizeSection(false), EnableMachineOutliner(false),
150+
EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
151+
EmitAddrsig(false), EmitCallSiteInfo(false),
152+
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
153+
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
154+
XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false),
155155
PPCGenScalarMASSEntries(false), JMCInstrument(false),
156156
EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false),
157157
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
@@ -295,6 +295,9 @@ namespace llvm {
295295
/// function in the runtime library..
296296
unsigned EmulatedTLS : 1;
297297

298+
/// EnableTLSDESC - This flag enables TLS Descriptors.
299+
unsigned EnableTLSDESC : 1;
300+
298301
/// This flag enables InterProcedural Register Allocation (IPRA).
299302
unsigned EnableIPRA : 1;
300303

llvm/include/llvm/TargetParser/Triple.h

+7
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,13 @@ class Triple {
10331033
isWindowsCygwinEnvironment() || isOHOSFamily();
10341034
}
10351035

1036+
/// Tests whether the target uses TLS Descriptor by default.
1037+
bool hasDefaultTLSDESC() const {
1038+
// TODO: Improve check for other platforms, like Android, and RISC-V
1039+
// Note: This is currently only used on RISC-V.
1040+
return isOSBinFormatELF() && isAArch64();
1041+
}
1042+
10361043
/// Tests whether the target uses -data-sections as default.
10371044
bool hasDefaultDataSections() const {
10381045
return isOSBinFormatXCOFF() || isWasm();

llvm/lib/CodeGen/CommandFlags.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ CGOPT(bool, XCOFFTracebackTable)
9393
CGOPT(std::string, BBSections)
9494
CGOPT(unsigned, TLSSize)
9595
CGOPT_EXP(bool, EmulatedTLS)
96+
CGOPT_EXP(bool, EnableTLSDESC)
9697
CGOPT(bool, UniqueSectionNames)
9798
CGOPT(bool, UniqueBasicBlockSectionNames)
9899
CGOPT(EABI, EABIVersion)
@@ -404,6 +405,11 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
404405
"emulated-tls", cl::desc("Use emulated TLS model"), cl::init(false));
405406
CGBINDOPT(EmulatedTLS);
406407

408+
static cl::opt<bool> EnableTLSDESC(
409+
"enable-tlsdesc", cl::desc("Enable the use of TLS Descriptors"),
410+
cl::init(false));
411+
CGBINDOPT(EnableTLSDESC);
412+
407413
static cl::opt<bool> UniqueSectionNames(
408414
"unique-section-names", cl::desc("Give unique names to every section"),
409415
cl::init(true));
@@ -568,6 +574,8 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
568574
Options.TLSSize = getTLSSize();
569575
Options.EmulatedTLS =
570576
getExplicitEmulatedTLS().value_or(TheTriple.hasDefaultEmulatedTLS());
577+
Options.EnableTLSDESC =
578+
getExplicitEnableTLSDESC().value_or(TheTriple.hasDefaultTLSDESC());
571579
Options.ExceptionModel = getExceptionModel();
572580
Options.EmitStackSizeSection = getEnableStackSizeSection();
573581
Options.EnableMachineFunctionSplitter = getEnableMachineFunctionSplitter();

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

+54-9
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ class RISCVAsmParser : public MCTargetAsmParser {
169169
// 'add' is an overloaded mnemonic.
170170
bool checkPseudoAddTPRel(MCInst &Inst, OperandVector &Operands);
171171

172+
// Checks that a PseudoTLSDESCCall is using x5/t0 in its output operand.
173+
// Enforcing this using a restricted register class for the output
174+
// operand of PseudoTLSDESCCall results in a poor diagnostic due to the fact
175+
// 'jalr' is an overloaded mnemonic.
176+
bool checkPseudoTLSDESCCall(MCInst &Inst, OperandVector &Operands);
177+
172178
// Check instruction constraints.
173179
bool validateInstruction(MCInst &Inst, OperandVector &Operands);
174180

@@ -549,6 +555,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
549555
VK == RISCVMCExpr::VK_RISCV_TPREL_ADD;
550556
}
551557

558+
bool isTLSDESCCallSymbol() const {
559+
int64_t Imm;
560+
RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None;
561+
// Must be of 'immediate' type but not a constant.
562+
if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
563+
return false;
564+
return RISCVAsmParser::classifySymbolRef(getImm(), VK) &&
565+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_CALL;
566+
}
567+
552568
bool isCSRSystemRegister() const { return isSystemRegister(); }
553569

554570
bool isVTypeImm(unsigned N) const {
@@ -601,7 +617,10 @@ struct RISCVOperand final : public MCParsedAsmOperand {
601617
if (!isImm())
602618
return false;
603619
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
604-
if (VK == RISCVMCExpr::VK_RISCV_LO || VK == RISCVMCExpr::VK_RISCV_PCREL_LO)
620+
if (VK == RISCVMCExpr::VK_RISCV_LO ||
621+
VK == RISCVMCExpr::VK_RISCV_PCREL_LO ||
622+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO ||
623+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO)
605624
return true;
606625
// Given only Imm, ensuring that the actually specified constant is either
607626
// a signed or unsigned 64-bit number is unfortunately impossible.
@@ -854,7 +873,9 @@ struct RISCVOperand final : public MCParsedAsmOperand {
854873
return IsValid && ((IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None) ||
855874
VK == RISCVMCExpr::VK_RISCV_LO ||
856875
VK == RISCVMCExpr::VK_RISCV_PCREL_LO ||
857-
VK == RISCVMCExpr::VK_RISCV_TPREL_LO);
876+
VK == RISCVMCExpr::VK_RISCV_TPREL_LO ||
877+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO ||
878+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO);
858879
}
859880

860881
bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); }
@@ -911,14 +932,16 @@ struct RISCVOperand final : public MCParsedAsmOperand {
911932
return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
912933
VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
913934
VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
914-
VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI);
915-
} else {
916-
return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None ||
917-
VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
918-
VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
919-
VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
920-
VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI);
935+
VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI ||
936+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI);
921937
}
938+
939+
return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None ||
940+
VK == RISCVMCExpr::VK_RISCV_PCREL_HI ||
941+
VK == RISCVMCExpr::VK_RISCV_GOT_HI ||
942+
VK == RISCVMCExpr::VK_RISCV_TLS_GOT_HI ||
943+
VK == RISCVMCExpr::VK_RISCV_TLS_GD_HI ||
944+
VK == RISCVMCExpr::VK_RISCV_TLSDESC_HI);
922945
}
923946

924947
bool isSImm21Lsb0JAL() const { return isBareSimmNLsb0<21>(); }
@@ -1556,6 +1579,11 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
15561579
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
15571580
return Error(ErrorLoc, "operand must be a symbol with %tprel_add modifier");
15581581
}
1582+
case Match_InvalidTLSDESCCallSymbol: {
1583+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
1584+
return Error(ErrorLoc,
1585+
"operand must be a symbol with %tlsdesc_call modifier");
1586+
}
15591587
case Match_InvalidRTZArg: {
15601588
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
15611589
return Error(ErrorLoc, "operand must be 'rtz' floating-point rounding mode");
@@ -3324,6 +3352,19 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst,
33243352
return false;
33253353
}
33263354

3355+
bool RISCVAsmParser::checkPseudoTLSDESCCall(MCInst &Inst,
3356+
OperandVector &Operands) {
3357+
assert(Inst.getOpcode() == RISCV::PseudoTLSDESCCall && "Invalid instruction");
3358+
assert(Inst.getOperand(0).isReg() && "Unexpected operand kind");
3359+
if (Inst.getOperand(0).getReg() != RISCV::X5) {
3360+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[3]).getStartLoc();
3361+
return Error(ErrorLoc, "the output operand must be t0/x5 when using "
3362+
"%tlsdesc_call modifier");
3363+
}
3364+
3365+
return false;
3366+
}
3367+
33273368
std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultMaskRegOp() const {
33283369
return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(),
33293370
llvm::SMLoc());
@@ -3559,6 +3600,10 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
35593600
if (checkPseudoAddTPRel(Inst, Operands))
35603601
return true;
35613602
break;
3603+
case RISCV::PseudoTLSDESCCall:
3604+
if (checkPseudoTLSDESCCall(Inst, Operands))
3605+
return true;
3606+
break;
35623607
case RISCV::PseudoSEXT_B:
35633608
emitPseudoExtend(Inst, /*SignExtend=*/true, /*Width=*/8, IDLoc, Out);
35643609
return false;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
8686
{"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
8787
{"fixup_riscv_relax", 0, 0, 0},
8888
{"fixup_riscv_align", 0, 0, 0},
89+
90+
{"fixup_riscv_tlsdesc_hi20", 12, 20,
91+
MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
92+
{"fixup_riscv_tlsdesc_load_lo12", 20, 12, 0},
93+
{"fixup_riscv_tlsdesc_add_lo12", 20, 12, 0},
94+
{"fixup_riscv_tlsdesc_call", 0, 0, 0},
8995
};
9096
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
9197
"Not all fixup kinds added to Infos array");
@@ -126,6 +132,7 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
126132
case RISCV::fixup_riscv_got_hi20:
127133
case RISCV::fixup_riscv_tls_got_hi20:
128134
case RISCV::fixup_riscv_tls_gd_hi20:
135+
case RISCV::fixup_riscv_tlsdesc_hi20:
129136
return true;
130137
}
131138

@@ -411,6 +418,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
411418
case RISCV::fixup_riscv_got_hi20:
412419
case RISCV::fixup_riscv_tls_got_hi20:
413420
case RISCV::fixup_riscv_tls_gd_hi20:
421+
case RISCV::fixup_riscv_tlsdesc_hi20:
414422
llvm_unreachable("Relocation should be unconditionally forced\n");
415423
case FK_Data_1:
416424
case FK_Data_2:
@@ -421,6 +429,7 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
421429
case RISCV::fixup_riscv_lo12_i:
422430
case RISCV::fixup_riscv_pcrel_lo12_i:
423431
case RISCV::fixup_riscv_tprel_lo12_i:
432+
case RISCV::fixup_riscv_tlsdesc_load_lo12:
424433
return Value & 0xfff;
425434
case RISCV::fixup_riscv_12_i:
426435
if (!isInt<12>(Value)) {
@@ -524,6 +533,7 @@ bool RISCVAsmBackend::evaluateTargetFixup(
524533
switch (Fixup.getTargetKind()) {
525534
default:
526535
llvm_unreachable("Unexpected fixup kind!");
536+
case RISCV::fixup_riscv_tlsdesc_hi20:
527537
case RISCV::fixup_riscv_pcrel_hi20:
528538
AUIPCFixup = &Fixup;
529539
AUIPCDF = DF;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,15 @@ enum {
264264
MO_TPREL_ADD = 10,
265265
MO_TLS_GOT_HI = 11,
266266
MO_TLS_GD_HI = 12,
267+
MO_TLSDESC_HI = 13,
268+
MO_TLSDESC_LOAD_LO = 14,
269+
MO_TLSDESC_ADD_LO = 15,
270+
MO_TLSDESC_CALL = 16,
267271

268272
// Used to differentiate between target-specific "direct" flags and "bitmask"
269273
// flags. A machine operand can only have one "direct" flag, but can have
270274
// multiple "bitmask" flags.
271-
MO_DIRECT_FLAG_MASK = 15
275+
MO_DIRECT_FLAG_MASK = 31
272276
};
273277
} // namespace RISCVII
274278

llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
7777
return ELF::R_RISCV_TLS_GOT_HI20;
7878
case RISCV::fixup_riscv_tls_gd_hi20:
7979
return ELF::R_RISCV_TLS_GD_HI20;
80+
case RISCV::fixup_riscv_tlsdesc_hi20:
81+
return ELF::R_RISCV_TLSDESC_HI20;
82+
case RISCV::fixup_riscv_tlsdesc_load_lo12:
83+
return ELF::R_RISCV_TLSDESC_LOAD_LO12;
84+
case RISCV::fixup_riscv_tlsdesc_add_lo12:
85+
return ELF::R_RISCV_TLSDESC_ADD_LO12;
86+
case RISCV::fixup_riscv_tlsdesc_call:
87+
return ELF::R_RISCV_TLSDESC_CALL;
8088
case RISCV::fixup_riscv_jal:
8189
return ELF::R_RISCV_JAL;
8290
case RISCV::fixup_riscv_branch:
@@ -96,6 +104,13 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
96104
default:
97105
Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");
98106
return ELF::R_RISCV_NONE;
107+
case RISCV::fixup_riscv_tlsdesc_load_lo12:
108+
return ELF::R_RISCV_TLSDESC_LOAD_LO12;
109+
case RISCV::fixup_riscv_tlsdesc_add_lo12:
110+
return ELF::R_RISCV_TLSDESC_ADD_LO12;
111+
case RISCV::fixup_riscv_tlsdesc_call:
112+
return ELF::R_RISCV_TLSDESC_CALL;
113+
99114
case FK_Data_1:
100115
Ctx.reportError(Fixup.getLoc(), "1-byte data relocations not supported");
101116
return ELF::R_RISCV_NONE;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ enum Fixups {
7171
// Used to generate an R_RISCV_ALIGN relocation, which indicates the linker
7272
// should fixup the alignment after linker relaxation.
7373
fixup_riscv_align,
74+
// Fixups indicating a TLS descriptor code sequence, corresponding to auipc,
75+
// lw/ld, addi, and jalr, respectively.
76+
fixup_riscv_tlsdesc_hi20,
77+
fixup_riscv_tlsdesc_load_lo12,
78+
fixup_riscv_tlsdesc_add_lo12,
79+
fixup_riscv_tlsdesc_call,
7480

7581
// Used as a sentinel, must be the last
7682
fixup_riscv_invalid,

0 commit comments

Comments
 (0)