Skip to content

Commit 21bfd06

Browse files
committed
[AArch64] Add support for the GNU ILP32 ABI
Add the aarch64[_be]-*-gnu_ilp32 targets to support the GNU ILP32 ABI for AArch64. The needed codegen changes were mostly already implemented in D61259, which added support for the watchOS ILP32 ABI. The main changes are: - Wiring up the new target to enable ILP32 codegen and MC. - ILP32 va_list support. - ILP32 TLSDESC relocation support. There was existing MC support for ELF ILP32 relocations from D25159 which could be enabled by passing "-target-abi ilp32" to llvm-mc. This was changed to check for "gnu_ilp32" in the target triple instead. This shouldn't cause any issues since the existing support was slightly broken: it was generating ELF64 objects instead of the ELF32 object files expected by the GNU ILP32 toolchain. This target has been tested by running the full rustc testsuite on a big-endian ILP32 system based on the GCC ILP32 toolchain. Reviewed By: kristof.beyls Differential Revision: https://reviews.llvm.org/D94143
1 parent 5d71837 commit 21bfd06

21 files changed

+282
-80
lines changed

llvm/include/llvm/ADT/Triple.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class Triple {
209209
GNUEABI,
210210
GNUEABIHF,
211211
GNUX32,
212+
GNUILP32,
212213
CODE16,
213214
EABI,
214215
EABIHF,
@@ -728,7 +729,10 @@ class Triple {
728729
assert(PointerWidth == 64 || PointerWidth == 32);
729730
if (!isAArch64())
730731
return false;
731-
return isArch64Bit() ? PointerWidth == 64 : PointerWidth == 32;
732+
return getArch() == Triple::aarch64_32 ||
733+
getEnvironment() == Triple::GNUILP32
734+
? PointerWidth == 32
735+
: PointerWidth == 64;
732736
}
733737

734738
/// Tests whether the target is MIPS 32-bit (little and big endian).

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,20 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
181181
// will be in memory. Most of these could end up >2GB away so even a signed
182182
// pc-relative 32-bit address is insufficient, theoretically.
183183
if (isPositionIndependent()) {
184-
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
185-
dwarf::DW_EH_PE_sdata8;
186-
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
187-
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
188-
dwarf::DW_EH_PE_sdata8;
184+
// ILP32 uses sdata4 instead of sdata8
185+
if (TgtM.getTargetTriple().getEnvironment() == Triple::GNUILP32) {
186+
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
187+
dwarf::DW_EH_PE_sdata4;
188+
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
189+
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
190+
dwarf::DW_EH_PE_sdata4;
191+
} else {
192+
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
193+
dwarf::DW_EH_PE_sdata8;
194+
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
195+
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
196+
dwarf::DW_EH_PE_sdata8;
197+
}
189198
} else {
190199
PersonalityEncoding = dwarf::DW_EH_PE_absptr;
191200
LSDAEncoding = dwarf::DW_EH_PE_absptr;

llvm/lib/Support/Triple.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
240240
case GNUEABI: return "gnueabi";
241241
case GNUEABIHF: return "gnueabihf";
242242
case GNUX32: return "gnux32";
243+
case GNUILP32: return "gnu_ilp32";
243244
case Itanium: return "itanium";
244245
case MSVC: return "msvc";
245246
case MacABI: return "macabi";
@@ -535,26 +536,27 @@ static Triple::OSType parseOS(StringRef OSName) {
535536

536537
static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {
537538
return StringSwitch<Triple::EnvironmentType>(EnvironmentName)
538-
.StartsWith("eabihf", Triple::EABIHF)
539-
.StartsWith("eabi", Triple::EABI)
540-
.StartsWith("gnuabin32", Triple::GNUABIN32)
541-
.StartsWith("gnuabi64", Triple::GNUABI64)
542-
.StartsWith("gnueabihf", Triple::GNUEABIHF)
543-
.StartsWith("gnueabi", Triple::GNUEABI)
544-
.StartsWith("gnux32", Triple::GNUX32)
545-
.StartsWith("code16", Triple::CODE16)
546-
.StartsWith("gnu", Triple::GNU)
547-
.StartsWith("android", Triple::Android)
548-
.StartsWith("musleabihf", Triple::MuslEABIHF)
549-
.StartsWith("musleabi", Triple::MuslEABI)
550-
.StartsWith("musl", Triple::Musl)
551-
.StartsWith("msvc", Triple::MSVC)
552-
.StartsWith("itanium", Triple::Itanium)
553-
.StartsWith("cygnus", Triple::Cygnus)
554-
.StartsWith("coreclr", Triple::CoreCLR)
555-
.StartsWith("simulator", Triple::Simulator)
556-
.StartsWith("macabi", Triple::MacABI)
557-
.Default(Triple::UnknownEnvironment);
539+
.StartsWith("eabihf", Triple::EABIHF)
540+
.StartsWith("eabi", Triple::EABI)
541+
.StartsWith("gnuabin32", Triple::GNUABIN32)
542+
.StartsWith("gnuabi64", Triple::GNUABI64)
543+
.StartsWith("gnueabihf", Triple::GNUEABIHF)
544+
.StartsWith("gnueabi", Triple::GNUEABI)
545+
.StartsWith("gnux32", Triple::GNUX32)
546+
.StartsWith("gnu_ilp32", Triple::GNUILP32)
547+
.StartsWith("code16", Triple::CODE16)
548+
.StartsWith("gnu", Triple::GNU)
549+
.StartsWith("android", Triple::Android)
550+
.StartsWith("musleabihf", Triple::MuslEABIHF)
551+
.StartsWith("musleabi", Triple::MuslEABI)
552+
.StartsWith("musl", Triple::Musl)
553+
.StartsWith("msvc", Triple::MSVC)
554+
.StartsWith("itanium", Triple::Itanium)
555+
.StartsWith("cygnus", Triple::Cygnus)
556+
.StartsWith("coreclr", Triple::CoreCLR)
557+
.StartsWith("simulator", Triple::Simulator)
558+
.StartsWith("macabi", Triple::MacABI)
559+
.Default(Triple::UnknownEnvironment);
558560
}
559561

560562
static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,17 +1272,28 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
12721272
EmitToStreamer(*OutStreamer, Adrp);
12731273

12741274
MCInst Ldr;
1275-
Ldr.setOpcode(AArch64::LDRXui);
1276-
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
1275+
if (STI->isTargetILP32()) {
1276+
Ldr.setOpcode(AArch64::LDRWui);
1277+
Ldr.addOperand(MCOperand::createReg(AArch64::W1));
1278+
} else {
1279+
Ldr.setOpcode(AArch64::LDRXui);
1280+
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
1281+
}
12771282
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
12781283
Ldr.addOperand(SymTLSDescLo12);
12791284
Ldr.addOperand(MCOperand::createImm(0));
12801285
EmitToStreamer(*OutStreamer, Ldr);
12811286

12821287
MCInst Add;
1283-
Add.setOpcode(AArch64::ADDXri);
1284-
Add.addOperand(MCOperand::createReg(AArch64::X0));
1285-
Add.addOperand(MCOperand::createReg(AArch64::X0));
1288+
if (STI->isTargetILP32()) {
1289+
Add.setOpcode(AArch64::ADDWri);
1290+
Add.addOperand(MCOperand::createReg(AArch64::W0));
1291+
Add.addOperand(MCOperand::createReg(AArch64::W0));
1292+
} else {
1293+
Add.setOpcode(AArch64::ADDXri);
1294+
Add.addOperand(MCOperand::createReg(AArch64::X0));
1295+
Add.addOperand(MCOperand::createReg(AArch64::X0));
1296+
}
12861297
Add.addOperand(SymTLSDescLo12);
12871298
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
12881299
EmitToStreamer(*OutStreamer, Add);

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7011,11 +7011,13 @@ SDValue AArch64TargetLowering::LowerWin64_VASTART(SDValue Op,
70117011
}
70127012

70137013
SDValue AArch64TargetLowering::LowerAAPCS_VASTART(SDValue Op,
7014-
SelectionDAG &DAG) const {
7014+
SelectionDAG &DAG) const {
70157015
// The layout of the va_list struct is specified in the AArch64 Procedure Call
70167016
// Standard, section B.3.
70177017
MachineFunction &MF = DAG.getMachineFunction();
70187018
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
7019+
unsigned PtrSize = Subtarget->isTargetILP32() ? 4 : 8;
7020+
auto PtrMemVT = getPointerMemTy(DAG.getDataLayout());
70197021
auto PtrVT = getPointerTy(DAG.getDataLayout());
70207022
SDLoc DL(Op);
70217023

@@ -7025,54 +7027,64 @@ SDValue AArch64TargetLowering::LowerAAPCS_VASTART(SDValue Op,
70257027
SmallVector<SDValue, 4> MemOps;
70267028

70277029
// void *__stack at offset 0
7030+
unsigned Offset = 0;
70287031
SDValue Stack = DAG.getFrameIndex(FuncInfo->getVarArgsStackIndex(), PtrVT);
7029-
MemOps.push_back(
7030-
DAG.getStore(Chain, DL, Stack, VAList, MachinePointerInfo(SV), Align(8)));
7032+
Stack = DAG.getZExtOrTrunc(Stack, DL, PtrMemVT);
7033+
MemOps.push_back(DAG.getStore(Chain, DL, Stack, VAList,
7034+
MachinePointerInfo(SV), Align(PtrSize)));
70317035

7032-
// void *__gr_top at offset 8
7036+
// void *__gr_top at offset 8 (4 on ILP32)
7037+
Offset += PtrSize;
70337038
int GPRSize = FuncInfo->getVarArgsGPRSize();
70347039
if (GPRSize > 0) {
70357040
SDValue GRTop, GRTopAddr;
70367041

7037-
GRTopAddr =
7038-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(8, DL, PtrVT));
7042+
GRTopAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
7043+
DAG.getConstant(Offset, DL, PtrVT));
70397044

70407045
GRTop = DAG.getFrameIndex(FuncInfo->getVarArgsGPRIndex(), PtrVT);
70417046
GRTop = DAG.getNode(ISD::ADD, DL, PtrVT, GRTop,
70427047
DAG.getConstant(GPRSize, DL, PtrVT));
7048+
GRTop = DAG.getZExtOrTrunc(GRTop, DL, PtrMemVT);
70437049

70447050
MemOps.push_back(DAG.getStore(Chain, DL, GRTop, GRTopAddr,
7045-
MachinePointerInfo(SV, 8), Align(8)));
7051+
MachinePointerInfo(SV, Offset),
7052+
Align(PtrSize)));
70467053
}
70477054

7048-
// void *__vr_top at offset 16
7055+
// void *__vr_top at offset 16 (8 on ILP32)
7056+
Offset += PtrSize;
70497057
int FPRSize = FuncInfo->getVarArgsFPRSize();
70507058
if (FPRSize > 0) {
70517059
SDValue VRTop, VRTopAddr;
70527060
VRTopAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
7053-
DAG.getConstant(16, DL, PtrVT));
7061+
DAG.getConstant(Offset, DL, PtrVT));
70547062

70557063
VRTop = DAG.getFrameIndex(FuncInfo->getVarArgsFPRIndex(), PtrVT);
70567064
VRTop = DAG.getNode(ISD::ADD, DL, PtrVT, VRTop,
70577065
DAG.getConstant(FPRSize, DL, PtrVT));
7066+
VRTop = DAG.getZExtOrTrunc(VRTop, DL, PtrMemVT);
70587067

70597068
MemOps.push_back(DAG.getStore(Chain, DL, VRTop, VRTopAddr,
7060-
MachinePointerInfo(SV, 16), Align(8)));
7069+
MachinePointerInfo(SV, Offset),
7070+
Align(PtrSize)));
70617071
}
70627072

7063-
// int __gr_offs at offset 24
7064-
SDValue GROffsAddr =
7065-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(24, DL, PtrVT));
7073+
// int __gr_offs at offset 24 (12 on ILP32)
7074+
Offset += PtrSize;
7075+
SDValue GROffsAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
7076+
DAG.getConstant(Offset, DL, PtrVT));
70667077
MemOps.push_back(
70677078
DAG.getStore(Chain, DL, DAG.getConstant(-GPRSize, DL, MVT::i32),
7068-
GROffsAddr, MachinePointerInfo(SV, 24), Align(4)));
7079+
GROffsAddr, MachinePointerInfo(SV, Offset), Align(4)));
70697080

7070-
// int __vr_offs at offset 28
7071-
SDValue VROffsAddr =
7072-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(28, DL, PtrVT));
7081+
// int __vr_offs at offset 28 (16 on ILP32)
7082+
Offset += 4;
7083+
SDValue VROffsAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
7084+
DAG.getConstant(Offset, DL, PtrVT));
70737085
MemOps.push_back(
70747086
DAG.getStore(Chain, DL, DAG.getConstant(-FPRSize, DL, MVT::i32),
7075-
VROffsAddr, MachinePointerInfo(SV, 28), Align(4)));
7087+
VROffsAddr, MachinePointerInfo(SV, Offset), Align(4)));
70767088

70777089
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps);
70787090
}
@@ -7095,8 +7107,10 @@ SDValue AArch64TargetLowering::LowerVACOPY(SDValue Op,
70957107
// pointer.
70967108
SDLoc DL(Op);
70977109
unsigned PtrSize = Subtarget->isTargetILP32() ? 4 : 8;
7098-
unsigned VaListSize = (Subtarget->isTargetDarwin() ||
7099-
Subtarget->isTargetWindows()) ? PtrSize : 32;
7110+
unsigned VaListSize =
7111+
(Subtarget->isTargetDarwin() || Subtarget->isTargetWindows())
7112+
? PtrSize
7113+
: Subtarget->isTargetILP32() ? 20 : 32;
71007114
const Value *DestSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
71017115
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
71027116

llvm/lib/Target/AArch64/AArch64Subtarget.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,10 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
482482
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
483483
bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }
484484

485-
bool isTargetILP32() const { return TargetTriple.isArch32Bit(); }
485+
bool isTargetILP32() const {
486+
return TargetTriple.isArch32Bit() ||
487+
TargetTriple.getEnvironment() == Triple::GNUILP32;
488+
}
486489

487490
bool useAA() const override { return UseAA; }
488491

llvm/lib/Target/AArch64/AArch64TargetMachine.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,18 +215,17 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
215215
static std::string computeDataLayout(const Triple &TT,
216216
const MCTargetOptions &Options,
217217
bool LittleEndian) {
218-
if (Options.getABIName() == "ilp32")
219-
return "e-m:e-p:32:32-i8:8-i16:16-i64:64-S128";
220218
if (TT.isOSBinFormatMachO()) {
221219
if (TT.getArch() == Triple::aarch64_32)
222220
return "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128";
223221
return "e-m:o-i64:64-i128:128-n32:64-S128";
224222
}
225223
if (TT.isOSBinFormatCOFF())
226224
return "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128";
227-
if (LittleEndian)
228-
return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
229-
return "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
225+
std::string Endian = LittleEndian ? "e" : "E";
226+
std::string Ptr32 = TT.getEnvironment() == Triple::GNUILP32 ? "-p:32:32" : "";
227+
return Endian + "-m:e" + Ptr32 +
228+
"-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
230229
}
231230

232231
static StringRef computeDefaultCPU(const Triple &TT, StringRef CPU) {
@@ -318,6 +317,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT,
318317
// MachO/CodeModel::Large, which GlobalISel does not support.
319318
if (getOptLevel() <= EnableGlobalISelAtO &&
320319
TT.getArch() != Triple::aarch64_32 &&
320+
TT.getEnvironment() != Triple::GNUILP32 &&
321321
!(getCodeModel() == CodeModel::Large && TT.isOSBinFormatMachO())) {
322322
setGlobalISel(true);
323323
setGlobalISelAbort(GlobalISelAbortMode::Disable);

llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
271271
AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
272272
const MCInstrInfo &MII, const MCTargetOptions &Options)
273273
: MCTargetAsmParser(Options, STI, MII) {
274-
IsILP32 = Options.getABIName() == "ilp32";
274+
IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
275275
MCAsmParserExtension::Initialize(Parser);
276276
MCStreamer &S = getParser().getStreamer();
277277
if (S.getTargetStreamer() == nullptr)

llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
758758
assert(TheTriple.isOSBinFormatELF() && "Invalid target");
759759

760760
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
761-
bool IsILP32 = Options.getABIName() == "ilp32";
761+
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
762762
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
763763
IsILP32);
764764
}
@@ -771,7 +771,7 @@ MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
771771
assert(TheTriple.isOSBinFormatELF() &&
772772
"Big endian is only supported for ELF targets!");
773773
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
774-
bool IsILP32 = Options.getABIName() == "ilp32";
774+
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
775775
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
776776
IsILP32);
777777
}

llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
4343
} // end anonymous namespace
4444

4545
AArch64ELFObjectWriter::AArch64ELFObjectWriter(uint8_t OSABI, bool IsILP32)
46-
: MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_AARCH64,
46+
: MCELFObjectTargetWriter(/*Is64Bit*/ !IsILP32, OSABI, ELF::EM_AARCH64,
4747
/*HasRelocationAddend*/ true),
4848
IsILP32(IsILP32) {}
4949

llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ AArch64MCAsmInfoELF::AArch64MCAsmInfoELF(const Triple &T) {
7373
// targeting ELF.
7474
AssemblerDialect = AsmWriterVariant == Default ? Generic : AsmWriterVariant;
7575

76-
CodePointerSize = 8;
76+
CodePointerSize = T.getEnvironment() == Triple::GNUILP32 ? 4 : 8;
7777

7878
// ".comm align is in bytes but .align is pow-2."
7979
AlignmentIsInBytes = false;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llc -mtriple=aarch64-linux-gnu_ilp32 -relocation-model=pic %s -o - | FileCheck %s
2+
; RUN: llc -mtriple=aarch64-linux-gnu_ilp32 -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
3+
4+
@var = thread_local global i32 zeroinitializer
5+
6+
define i32 @test_thread_local() {
7+
; CHECK-LABEL: test_thread_local:
8+
9+
%val = load i32, i32* @var
10+
ret i32 %val
11+
12+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:var
13+
; CHECK-NEXT: ldr w[[CALLEE:[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:var]
14+
; CHECK-NEXT: add w0, w[[TLSDESC_HI]], :tlsdesc_lo12:var
15+
; CHECK-NEXT: .tlsdesccall var
16+
; CHECK-NEXT: blr x[[CALLEE]]
17+
18+
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_ADR_PAGE21
19+
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_LD32_LO12
20+
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_ADD_LO12
21+
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_CALL
22+
}

0 commit comments

Comments
 (0)