Skip to content

Commit 70d09f2

Browse files
authored
[AArch64] Add support for the GNU ILP32 ABI (#88)
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 f9a8d70 commit 70d09f2

21 files changed

+276
-78
lines changed

llvm/include/llvm/ADT/Triple.h

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ class Triple {
206206
GNUEABI,
207207
GNUEABIHF,
208208
GNUX32,
209+
GNUILP32,
209210
CODE16,
210211
EABI,
211212
EABIHF,

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,20 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
174174
// will be in memory. Most of these could end up >2GB away so even a signed
175175
// pc-relative 32-bit address is insufficient, theoretically.
176176
if (isPositionIndependent()) {
177-
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
178-
dwarf::DW_EH_PE_sdata8;
179-
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
180-
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
181-
dwarf::DW_EH_PE_sdata8;
177+
// ILP32 uses sdata4 instead of sdata8
178+
if (TgtM.getTargetTriple().getEnvironment() == Triple::GNUILP32) {
179+
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
180+
dwarf::DW_EH_PE_sdata4;
181+
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
182+
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
183+
dwarf::DW_EH_PE_sdata4;
184+
} else {
185+
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
186+
dwarf::DW_EH_PE_sdata8;
187+
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
188+
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
189+
dwarf::DW_EH_PE_sdata8;
190+
}
182191
} else {
183192
PersonalityEncoding = dwarf::DW_EH_PE_absptr;
184193
LSDAEncoding = dwarf::DW_EH_PE_absptr;

llvm/lib/Support/Triple.cpp

+22-20
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
238238
case GNUEABI: return "gnueabi";
239239
case GNUEABIHF: return "gnueabihf";
240240
case GNUX32: return "gnux32";
241+
case GNUILP32: return "gnu_ilp32";
241242
case Itanium: return "itanium";
242243
case MSVC: return "msvc";
243244
case MacABI: return "macabi";
@@ -529,26 +530,27 @@ static Triple::OSType parseOS(StringRef OSName) {
529530

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

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

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -1172,17 +1172,28 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
11721172
EmitToStreamer(*OutStreamer, Adrp);
11731173

11741174
MCInst Ldr;
1175-
Ldr.setOpcode(AArch64::LDRXui);
1176-
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
1175+
if (STI->isTargetILP32()) {
1176+
Ldr.setOpcode(AArch64::LDRWui);
1177+
Ldr.addOperand(MCOperand::createReg(AArch64::W1));
1178+
} else {
1179+
Ldr.setOpcode(AArch64::LDRXui);
1180+
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
1181+
}
11771182
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
11781183
Ldr.addOperand(SymTLSDescLo12);
11791184
Ldr.addOperand(MCOperand::createImm(0));
11801185
EmitToStreamer(*OutStreamer, Ldr);
11811186

11821187
MCInst Add;
1183-
Add.setOpcode(AArch64::ADDXri);
1184-
Add.addOperand(MCOperand::createReg(AArch64::X0));
1185-
Add.addOperand(MCOperand::createReg(AArch64::X0));
1188+
if (STI->isTargetILP32()) {
1189+
Add.setOpcode(AArch64::ADDWri);
1190+
Add.addOperand(MCOperand::createReg(AArch64::W0));
1191+
Add.addOperand(MCOperand::createReg(AArch64::W0));
1192+
} else {
1193+
Add.setOpcode(AArch64::ADDXri);
1194+
Add.addOperand(MCOperand::createReg(AArch64::X0));
1195+
Add.addOperand(MCOperand::createReg(AArch64::X0));
1196+
}
11861197
Add.addOperand(SymTLSDescLo12);
11871198
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
11881199
EmitToStreamer(*OutStreamer, Add);

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

+32-19
Original file line numberDiff line numberDiff line change
@@ -6057,11 +6057,13 @@ SDValue AArch64TargetLowering::LowerWin64_VASTART(SDValue Op,
60576057
}
60586058

60596059
SDValue AArch64TargetLowering::LowerAAPCS_VASTART(SDValue Op,
6060-
SelectionDAG &DAG) const {
6060+
SelectionDAG &DAG) const {
60616061
// The layout of the va_list struct is specified in the AArch64 Procedure Call
60626062
// Standard, section B.3.
60636063
MachineFunction &MF = DAG.getMachineFunction();
60646064
AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
6065+
unsigned PtrSize = Subtarget->isTargetILP32() ? 4 : 8;
6066+
auto PtrMemVT = getPointerMemTy(DAG.getDataLayout());
60656067
auto PtrVT = getPointerTy(DAG.getDataLayout());
60666068
SDLoc DL(Op);
60676069

@@ -6071,56 +6073,65 @@ SDValue AArch64TargetLowering::LowerAAPCS_VASTART(SDValue Op,
60716073
SmallVector<SDValue, 4> MemOps;
60726074

60736075
// void *__stack at offset 0
6076+
unsigned Offset = 0;
60746077
SDValue Stack = DAG.getFrameIndex(FuncInfo->getVarArgsStackIndex(), PtrVT);
6078+
Stack = DAG.getZExtOrTrunc(Stack, DL, PtrMemVT);
60756079
MemOps.push_back(DAG.getStore(Chain, DL, Stack, VAList,
6076-
MachinePointerInfo(SV), /* Alignment = */ 8));
6080+
MachinePointerInfo(SV),
6081+
/* Alignment = */ PtrSize));
60776082

6078-
// void *__gr_top at offset 8
6083+
// void *__gr_top at offset 8 (4 on ILP32)
6084+
Offset += PtrSize;
60796085
int GPRSize = FuncInfo->getVarArgsGPRSize();
60806086
if (GPRSize > 0) {
60816087
SDValue GRTop, GRTopAddr;
60826088

6083-
GRTopAddr =
6084-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(8, DL, PtrVT));
6089+
GRTopAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
6090+
DAG.getConstant(Offset, DL, PtrVT));
60856091

60866092
GRTop = DAG.getFrameIndex(FuncInfo->getVarArgsGPRIndex(), PtrVT);
60876093
GRTop = DAG.getNode(ISD::ADD, DL, PtrVT, GRTop,
60886094
DAG.getConstant(GPRSize, DL, PtrVT));
6095+
GRTop = DAG.getZExtOrTrunc(GRTop, DL, PtrMemVT);
60896096

60906097
MemOps.push_back(DAG.getStore(Chain, DL, GRTop, GRTopAddr,
6091-
MachinePointerInfo(SV, 8),
6092-
/* Alignment = */ 8));
6098+
MachinePointerInfo(SV, Offset),
6099+
/* Alignment = */ PtrSize));
60936100
}
60946101

6095-
// void *__vr_top at offset 16
6102+
// void *__vr_top at offset 16 (8 on ILP32)
6103+
Offset += PtrSize;
60966104
int FPRSize = FuncInfo->getVarArgsFPRSize();
60976105
if (FPRSize > 0) {
60986106
SDValue VRTop, VRTopAddr;
60996107
VRTopAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
6100-
DAG.getConstant(16, DL, PtrVT));
6108+
DAG.getConstant(Offset, DL, PtrVT));
61016109

61026110
VRTop = DAG.getFrameIndex(FuncInfo->getVarArgsFPRIndex(), PtrVT);
61036111
VRTop = DAG.getNode(ISD::ADD, DL, PtrVT, VRTop,
61046112
DAG.getConstant(FPRSize, DL, PtrVT));
6113+
VRTop = DAG.getZExtOrTrunc(VRTop, DL, PtrMemVT);
61056114

61066115
MemOps.push_back(DAG.getStore(Chain, DL, VRTop, VRTopAddr,
6107-
MachinePointerInfo(SV, 16),
6108-
/* Alignment = */ 8));
6116+
MachinePointerInfo(SV, Offset),
6117+
/* Alignment = */ PtrSize));
61096118
}
61106119

6111-
// int __gr_offs at offset 24
6120+
// int __gr_offs at offset 24 (12 on ILP32)
6121+
Offset += PtrSize;
61126122
SDValue GROffsAddr =
6113-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(24, DL, PtrVT));
6123+
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(Offset, DL, PtrVT));
61146124
MemOps.push_back(DAG.getStore(
61156125
Chain, DL, DAG.getConstant(-GPRSize, DL, MVT::i32), GROffsAddr,
6116-
MachinePointerInfo(SV, 24), /* Alignment = */ 4));
6126+
MachinePointerInfo(SV, Offset), /* Alignment = */ 4));
61176127

6118-
// int __vr_offs at offset 28
6128+
// int __vr_offs at offset 28 (16 on ILP32)
6129+
Offset += 4;
61196130
SDValue VROffsAddr =
6120-
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(28, DL, PtrVT));
6131+
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(Offset, DL, PtrVT));
61216132
MemOps.push_back(DAG.getStore(
61226133
Chain, DL, DAG.getConstant(-FPRSize, DL, MVT::i32), VROffsAddr,
6123-
MachinePointerInfo(SV, 28), /* Alignment = */ 4));
6134+
MachinePointerInfo(SV, Offset), /* Alignment = */ 4));
61246135

61256136
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps);
61266137
}
@@ -6143,8 +6154,10 @@ SDValue AArch64TargetLowering::LowerVACOPY(SDValue Op,
61436154
// pointer.
61446155
SDLoc DL(Op);
61456156
unsigned PtrSize = Subtarget->isTargetILP32() ? 4 : 8;
6146-
unsigned VaListSize = (Subtarget->isTargetDarwin() ||
6147-
Subtarget->isTargetWindows()) ? PtrSize : 32;
6157+
unsigned VaListSize =
6158+
(Subtarget->isTargetDarwin() || Subtarget->isTargetWindows())
6159+
? PtrSize
6160+
: Subtarget->isTargetILP32() ? 20 : 32;
61486161
const Value *DestSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
61496162
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
61506163

llvm/lib/Target/AArch64/AArch64Subtarget.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,10 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
461461
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
462462
bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }
463463

464-
bool isTargetILP32() const { return TargetTriple.isArch32Bit(); }
464+
bool isTargetILP32() const {
465+
return TargetTriple.isArch32Bit() ||
466+
TargetTriple.getEnvironment() == Triple::GNUILP32;
467+
}
465468

466469
bool useAA() const override { return UseAA; }
467470

llvm/lib/Target/AArch64/AArch64TargetMachine.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -213,18 +213,17 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
213213
static std::string computeDataLayout(const Triple &TT,
214214
const MCTargetOptions &Options,
215215
bool LittleEndian) {
216-
if (Options.getABIName() == "ilp32")
217-
return "e-m:e-p:32:32-i8:8-i16:16-i64:64-S128";
218216
if (TT.isOSBinFormatMachO()) {
219217
if (TT.getArch() == Triple::aarch64_32)
220218
return "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128";
221219
return "e-m:o-i64:64-i128:128-n32:64-S128";
222220
}
223221
if (TT.isOSBinFormatCOFF())
224222
return "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128";
225-
if (LittleEndian)
226-
return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
227-
return "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
223+
std::string Endian = LittleEndian ? "e" : "E";
224+
std::string Ptr32 = TT.getEnvironment() == Triple::GNUILP32 ? "-p:32:32" : "";
225+
return Endian + "-m:e" + Ptr32 +
226+
"-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
228227
}
229228

230229
static Reloc::Model getEffectiveRelocModel(const Triple &TT,
@@ -309,6 +308,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT,
309308
// MachO/CodeModel::Large, which GlobalISel does not support.
310309
if (getOptLevel() <= EnableGlobalISelAtO &&
311310
TT.getArch() != Triple::aarch64_32 &&
311+
TT.getEnvironment() != Triple::GNUILP32 &&
312312
!(getCodeModel() == CodeModel::Large && TT.isOSBinFormatMachO())) {
313313
setGlobalISel(true);
314314
setGlobalISelAbort(GlobalISelAbortMode::Disable);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
238238
AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
239239
const MCInstrInfo &MII, const MCTargetOptions &Options)
240240
: MCTargetAsmParser(Options, STI, MII) {
241-
IsILP32 = Options.getABIName() == "ilp32";
241+
IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
242242
MCAsmParserExtension::Initialize(Parser);
243243
MCStreamer &S = getParser().getStreamer();
244244
if (S.getTargetStreamer() == nullptr)

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
781781
assert(TheTriple.isOSBinFormatELF() && "Invalid target");
782782

783783
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
784-
bool IsILP32 = Options.getABIName() == "ilp32";
784+
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
785785
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
786786
IsILP32);
787787
}
@@ -794,7 +794,7 @@ MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
794794
assert(TheTriple.isOSBinFormatELF() &&
795795
"Big endian is only supported for ELF targets!");
796796
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
797-
bool IsILP32 = Options.getABIName() == "ilp32";
797+
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
798798
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
799799
IsILP32);
800800
}

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

+1-1
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

+1-1
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;
+22
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)