Skip to content

Commit f8ccc69

Browse files
committed
[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 riscv-non-isa/riscv-elf-psabi-doc#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 -enable-tlsdesc codegen flag.
1 parent 1f6f199 commit f8ccc69

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)