Skip to content

[AArch64] Add support for the GNU ILP32 ABI #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/include/llvm/ADT/Triple.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class Triple {
GNUEABI,
GNUEABIHF,
GNUX32,
GNUILP32,
CODE16,
EABI,
EABIHF,
Expand Down
19 changes: 14 additions & 5 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,20 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx,
// will be in memory. Most of these could end up >2GB away so even a signed
// pc-relative 32-bit address is insufficient, theoretically.
if (isPositionIndependent()) {
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata8;
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata8;
// ILP32 uses sdata4 instead of sdata8
if (TgtM.getTargetTriple().getEnvironment() == Triple::GNUILP32) {
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata4;
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata4;
} else {
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata8;
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8;
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_sdata8;
}
} else {
PersonalityEncoding = dwarf::DW_EH_PE_absptr;
LSDAEncoding = dwarf::DW_EH_PE_absptr;
Expand Down
42 changes: 22 additions & 20 deletions llvm/lib/Support/Triple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) {
case GNUEABI: return "gnueabi";
case GNUEABIHF: return "gnueabihf";
case GNUX32: return "gnux32";
case GNUILP32: return "gnu_ilp32";
case Itanium: return "itanium";
case MSVC: return "msvc";
case MacABI: return "macabi";
Expand Down Expand Up @@ -529,26 +530,27 @@ static Triple::OSType parseOS(StringRef OSName) {

static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {
return StringSwitch<Triple::EnvironmentType>(EnvironmentName)
.StartsWith("eabihf", Triple::EABIHF)
.StartsWith("eabi", Triple::EABI)
.StartsWith("gnuabin32", Triple::GNUABIN32)
.StartsWith("gnuabi64", Triple::GNUABI64)
.StartsWith("gnueabihf", Triple::GNUEABIHF)
.StartsWith("gnueabi", Triple::GNUEABI)
.StartsWith("gnux32", Triple::GNUX32)
.StartsWith("code16", Triple::CODE16)
.StartsWith("gnu", Triple::GNU)
.StartsWith("android", Triple::Android)
.StartsWith("musleabihf", Triple::MuslEABIHF)
.StartsWith("musleabi", Triple::MuslEABI)
.StartsWith("musl", Triple::Musl)
.StartsWith("msvc", Triple::MSVC)
.StartsWith("itanium", Triple::Itanium)
.StartsWith("cygnus", Triple::Cygnus)
.StartsWith("coreclr", Triple::CoreCLR)
.StartsWith("simulator", Triple::Simulator)
.StartsWith("macabi", Triple::MacABI)
.Default(Triple::UnknownEnvironment);
.StartsWith("eabihf", Triple::EABIHF)
.StartsWith("eabi", Triple::EABI)
.StartsWith("gnuabin32", Triple::GNUABIN32)
.StartsWith("gnuabi64", Triple::GNUABI64)
.StartsWith("gnueabihf", Triple::GNUEABIHF)
.StartsWith("gnueabi", Triple::GNUEABI)
.StartsWith("gnux32", Triple::GNUX32)
.StartsWith("gnu_ilp32", Triple::GNUILP32)
.StartsWith("code16", Triple::CODE16)
.StartsWith("gnu", Triple::GNU)
.StartsWith("android", Triple::Android)
.StartsWith("musleabihf", Triple::MuslEABIHF)
.StartsWith("musleabi", Triple::MuslEABI)
.StartsWith("musl", Triple::Musl)
.StartsWith("msvc", Triple::MSVC)
.StartsWith("itanium", Triple::Itanium)
.StartsWith("cygnus", Triple::Cygnus)
.StartsWith("coreclr", Triple::CoreCLR)
.StartsWith("simulator", Triple::Simulator)
.StartsWith("macabi", Triple::MacABI)
.Default(Triple::UnknownEnvironment);
}

static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {
Expand Down
21 changes: 16 additions & 5 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1172,17 +1172,28 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, Adrp);

MCInst Ldr;
Ldr.setOpcode(AArch64::LDRXui);
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
if (STI->isTargetILP32()) {
Ldr.setOpcode(AArch64::LDRWui);
Ldr.addOperand(MCOperand::createReg(AArch64::W1));
} else {
Ldr.setOpcode(AArch64::LDRXui);
Ldr.addOperand(MCOperand::createReg(AArch64::X1));
}
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
Ldr.addOperand(SymTLSDescLo12);
Ldr.addOperand(MCOperand::createImm(0));
EmitToStreamer(*OutStreamer, Ldr);

MCInst Add;
Add.setOpcode(AArch64::ADDXri);
Add.addOperand(MCOperand::createReg(AArch64::X0));
Add.addOperand(MCOperand::createReg(AArch64::X0));
if (STI->isTargetILP32()) {
Add.setOpcode(AArch64::ADDWri);
Add.addOperand(MCOperand::createReg(AArch64::W0));
Add.addOperand(MCOperand::createReg(AArch64::W0));
} else {
Add.setOpcode(AArch64::ADDXri);
Add.addOperand(MCOperand::createReg(AArch64::X0));
Add.addOperand(MCOperand::createReg(AArch64::X0));
}
Add.addOperand(SymTLSDescLo12);
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
EmitToStreamer(*OutStreamer, Add);
Expand Down
51 changes: 32 additions & 19 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6057,11 +6057,13 @@ SDValue AArch64TargetLowering::LowerWin64_VASTART(SDValue Op,
}

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

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

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

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

GRTopAddr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(8, DL, PtrVT));
GRTopAddr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList,
DAG.getConstant(Offset, DL, PtrVT));

GRTop = DAG.getFrameIndex(FuncInfo->getVarArgsGPRIndex(), PtrVT);
GRTop = DAG.getNode(ISD::ADD, DL, PtrVT, GRTop,
DAG.getConstant(GPRSize, DL, PtrVT));
GRTop = DAG.getZExtOrTrunc(GRTop, DL, PtrMemVT);

MemOps.push_back(DAG.getStore(Chain, DL, GRTop, GRTopAddr,
MachinePointerInfo(SV, 8),
/* Alignment = */ 8));
MachinePointerInfo(SV, Offset),
/* Alignment = */ PtrSize));
}

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

VRTop = DAG.getFrameIndex(FuncInfo->getVarArgsFPRIndex(), PtrVT);
VRTop = DAG.getNode(ISD::ADD, DL, PtrVT, VRTop,
DAG.getConstant(FPRSize, DL, PtrVT));
VRTop = DAG.getZExtOrTrunc(VRTop, DL, PtrMemVT);

MemOps.push_back(DAG.getStore(Chain, DL, VRTop, VRTopAddr,
MachinePointerInfo(SV, 16),
/* Alignment = */ 8));
MachinePointerInfo(SV, Offset),
/* Alignment = */ PtrSize));
}

// int __gr_offs at offset 24
// int __gr_offs at offset 24 (12 on ILP32)
Offset += PtrSize;
SDValue GROffsAddr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(24, DL, PtrVT));
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(Offset, DL, PtrVT));
MemOps.push_back(DAG.getStore(
Chain, DL, DAG.getConstant(-GPRSize, DL, MVT::i32), GROffsAddr,
MachinePointerInfo(SV, 24), /* Alignment = */ 4));
MachinePointerInfo(SV, Offset), /* Alignment = */ 4));

// int __vr_offs at offset 28
// int __vr_offs at offset 28 (16 on ILP32)
Offset += 4;
SDValue VROffsAddr =
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(28, DL, PtrVT));
DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(Offset, DL, PtrVT));
MemOps.push_back(DAG.getStore(
Chain, DL, DAG.getConstant(-FPRSize, DL, MVT::i32), VROffsAddr,
MachinePointerInfo(SV, 28), /* Alignment = */ 4));
MachinePointerInfo(SV, Offset), /* Alignment = */ 4));

return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps);
}
Expand All @@ -6143,8 +6154,10 @@ SDValue AArch64TargetLowering::LowerVACOPY(SDValue Op,
// pointer.
SDLoc DL(Op);
unsigned PtrSize = Subtarget->isTargetILP32() ? 4 : 8;
unsigned VaListSize = (Subtarget->isTargetDarwin() ||
Subtarget->isTargetWindows()) ? PtrSize : 32;
unsigned VaListSize =
(Subtarget->isTargetDarwin() || Subtarget->isTargetWindows())
? PtrSize
: Subtarget->isTargetILP32() ? 20 : 32;
const Value *DestSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();

Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Target/AArch64/AArch64Subtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,10 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }

bool isTargetILP32() const { return TargetTriple.isArch32Bit(); }
bool isTargetILP32() const {
return TargetTriple.isArch32Bit() ||
TargetTriple.getEnvironment() == Triple::GNUILP32;
}

bool useAA() const override { return UseAA; }

Expand Down
10 changes: 5 additions & 5 deletions llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,17 @@ static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
static std::string computeDataLayout(const Triple &TT,
const MCTargetOptions &Options,
bool LittleEndian) {
if (Options.getABIName() == "ilp32")
return "e-m:e-p:32:32-i8:8-i16:16-i64:64-S128";
if (TT.isOSBinFormatMachO()) {
if (TT.getArch() == Triple::aarch64_32)
return "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128";
return "e-m:o-i64:64-i128:128-n32:64-S128";
}
if (TT.isOSBinFormatCOFF())
return "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128";
if (LittleEndian)
return "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
return "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
std::string Endian = LittleEndian ? "e" : "E";
std::string Ptr32 = TT.getEnvironment() == Triple::GNUILP32 ? "-p:32:32" : "";
return Endian + "-m:e" + Ptr32 +
"-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128";
}

static Reloc::Model getEffectiveRelocModel(const Triple &TT,
Expand Down Expand Up @@ -309,6 +308,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT,
// MachO/CodeModel::Large, which GlobalISel does not support.
if (getOptLevel() <= EnableGlobalISelAtO &&
TT.getArch() != Triple::aarch64_32 &&
TT.getEnvironment() != Triple::GNUILP32 &&
!(getCodeModel() == CodeModel::Large && TT.isOSBinFormatMachO())) {
setGlobalISel(true);
setGlobalISelAbort(GlobalISelAbortMode::Disable);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
AArch64AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
const MCInstrInfo &MII, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, STI, MII) {
IsILP32 = Options.getABIName() == "ilp32";
IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
MCAsmParserExtension::Initialize(Parser);
MCStreamer &S = getParser().getStreamer();
if (S.getTargetStreamer() == nullptr)
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
assert(TheTriple.isOSBinFormatELF() && "Invalid target");

uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = Options.getABIName() == "ilp32";
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
IsILP32);
}
Expand All @@ -794,7 +794,7 @@ MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
assert(TheTriple.isOSBinFormatELF() &&
"Big endian is only supported for ELF targets!");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = Options.getABIName() == "ilp32";
bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32;
return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
IsILP32);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class AArch64ELFObjectWriter : public MCELFObjectTargetWriter {
} // end anonymous namespace

AArch64ELFObjectWriter::AArch64ELFObjectWriter(uint8_t OSABI, bool IsILP32)
: MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_AARCH64,
: MCELFObjectTargetWriter(/*Is64Bit*/ !IsILP32, OSABI, ELF::EM_AARCH64,
/*HasRelocationAddend*/ true),
IsILP32(IsILP32) {}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ AArch64MCAsmInfoELF::AArch64MCAsmInfoELF(const Triple &T) {
// targeting ELF.
AssemblerDialect = AsmWriterVariant == Default ? Generic : AsmWriterVariant;

CodePointerSize = 8;
CodePointerSize = T.getEnvironment() == Triple::GNUILP32 ? 4 : 8;

// ".comm align is in bytes but .align is pow-2."
AlignmentIsInBytes = false;
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/CodeGen/AArch64/ilp32-tlsdesc.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: llc -mtriple=aarch64-linux-gnu_ilp32 -relocation-model=pic %s -o - | FileCheck %s
; RUN: llc -mtriple=aarch64-linux-gnu_ilp32 -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s

@var = thread_local global i32 zeroinitializer

define i32 @test_thread_local() {
; CHECK-LABEL: test_thread_local:

%val = load i32, i32* @var
ret i32 %val

; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:var
; CHECK-NEXT: ldr w[[CALLEE:[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:var]
; CHECK-NEXT: add w0, w[[TLSDESC_HI]], :tlsdesc_lo12:var
; CHECK-NEXT: .tlsdesccall var
; CHECK-NEXT: blr x[[CALLEE]]

; CHECK-RELOC: R_AARCH64_P32_TLSDESC_ADR_PAGE21
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_LD32_LO12
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_ADD_LO12
; CHECK-RELOC: R_AARCH64_P32_TLSDESC_CALL
}
Loading