Skip to content

Commit 350019e

Browse files
committed
[AArch64][GlobalISel] Implement selectVaStartAAPCS
This commit adds the missing support for varargs in the instruction selection pass for AAPCS. Previously we only implemented this for Darwin. The implementation was according to AAPCS and SelectionDAG's LowerAAPCS_VASTART. It resolves all VA_START fallbacks in RAJAperf, llvm-test-suite, and SPEC CPU2017. These benchmarks now compile and pass without fallbacks due to varargs.
1 parent 7b4b85b commit 350019e

File tree

3 files changed

+996
-1
lines changed

3 files changed

+996
-1
lines changed

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1994,7 +1994,108 @@ bool AArch64InstructionSelector::selectVectorAshrLshr(
19941994

19951995
bool AArch64InstructionSelector::selectVaStartAAPCS(
19961996
MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const {
1997-
return false;
1997+
1998+
if (MF.getSubtarget<AArch64Subtarget>().isCallingConvWin64(
1999+
MF.getFunction().getCallingConv(), MF.getFunction().isVarArg()))
2000+
return false;
2001+
2002+
// The layout of the va_list struct is specified in the AArch64 Procedure Call
2003+
// Standard, section 10.1.5.
2004+
2005+
const AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
2006+
const unsigned PtrSize = STI.isTargetILP32() ? 4 : 8;
2007+
const auto *PtrRegClass =
2008+
STI.isTargetILP32() ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
2009+
2010+
const MCInstrDesc &MCIDAddAddr =
2011+
TII.get(STI.isTargetILP32() ? AArch64::ADDWri : AArch64::ADDXri);
2012+
const MCInstrDesc &MCIDStoreAddr =
2013+
TII.get(STI.isTargetILP32() ? AArch64::STRWui : AArch64::STRXui);
2014+
2015+
/*
2016+
* typedef struct va_list {
2017+
* void * stack; // next stack param
2018+
* void * gr_top; // end of GP arg reg save area
2019+
* void * vr_top; // end of FP/SIMD arg reg save area
2020+
* int gr_offs; // offset from gr_top to next GP register arg
2021+
* int vr_offs; // offset from vr_top to next FP/SIMD register arg
2022+
* } va_list;
2023+
*/
2024+
const auto VAList = I.getOperand(0).getReg();
2025+
2026+
// Our current offset in bytes from the va_list struct (VAList).
2027+
unsigned OffsetBytes = 0;
2028+
2029+
// Helper function to store (FrameIndex + Imm) to VAList at offset OffsetBytes
2030+
// and increment OffsetBytes by PtrSize.
2031+
const auto PushAddress = [&](const int FrameIndex, const int64_t Imm) {
2032+
const Register Top = MRI.createVirtualRegister(PtrRegClass);
2033+
auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), MCIDAddAddr)
2034+
.addDef(Top)
2035+
.addFrameIndex(FrameIndex)
2036+
.addImm(Imm)
2037+
.addImm(0);
2038+
constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
2039+
2040+
MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), MCIDStoreAddr)
2041+
.addUse(Top)
2042+
.addUse(VAList)
2043+
.addImm(OffsetBytes / PtrSize)
2044+
.addMemOperand(MF.getMachineMemOperand(
2045+
(*I.memoperands_begin())
2046+
->getPointerInfo()
2047+
.getWithOffset(OffsetBytes),
2048+
MachineMemOperand::MOStore, PtrSize, Align(PtrSize)));
2049+
constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
2050+
2051+
OffsetBytes += PtrSize;
2052+
};
2053+
2054+
// void* stack at offset 0
2055+
PushAddress(FuncInfo->getVarArgsStackIndex(), 0);
2056+
2057+
// void* gr_top at offset 8 (4 on ILP32)
2058+
const unsigned GPRSize = FuncInfo->getVarArgsGPRSize();
2059+
PushAddress(FuncInfo->getVarArgsGPRIndex(), GPRSize);
2060+
2061+
// void* vr_top at offset 16 (8 on ILP32)
2062+
const unsigned FPRSize = FuncInfo->getVarArgsFPRSize();
2063+
PushAddress(FuncInfo->getVarArgsFPRIndex(), FPRSize);
2064+
2065+
// Helper function to store a 4-byte integer constant to VAList at offset
2066+
// OffsetBytes, and increment OffsetBytes by 4.
2067+
const auto PushIntConstant = [&](const int32_t Value) {
2068+
constexpr int IntSize = 4;
2069+
const Register Temp = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2070+
auto MIB =
2071+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::MOVi32imm))
2072+
.addDef(Temp)
2073+
.addImm(Value);
2074+
constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
2075+
2076+
MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::STRWui))
2077+
.addUse(Temp)
2078+
.addUse(VAList)
2079+
.addImm(OffsetBytes / IntSize)
2080+
.addMemOperand(MF.getMachineMemOperand(
2081+
(*I.memoperands_begin())
2082+
->getPointerInfo()
2083+
.getWithOffset(OffsetBytes),
2084+
MachineMemOperand::MOStore, IntSize, Align(IntSize)));
2085+
constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
2086+
OffsetBytes += IntSize;
2087+
};
2088+
2089+
// int gr_offs at offset 24 (12 on ILP32)
2090+
PushIntConstant(-static_cast<int32_t>(GPRSize));
2091+
2092+
// int vr_offs at offset 28 (16 on ILP32)
2093+
PushIntConstant(-static_cast<int32_t>(FPRSize));
2094+
2095+
assert(OffsetBytes == (STI.isTargetILP32() ? 20 : 32) && "Unexpected offset");
2096+
2097+
I.eraseFromParent();
2098+
return true;
19982099
}
19992100

20002101
bool AArch64InstructionSelector::selectVaStartDarwin(

0 commit comments

Comments
 (0)