This change adds a support for a preserve_most calling convention to the AArch64 backend, similar to how it was done for X86-64.
There is also a subsequent patch on top of this one to add a tail-calls support for this calling convention.
Differential Revision: http://reviews.llvm.org/D18016
llvm-svn: 263092
(sequence "Q%u", 0, 31))>;
def CSR_AArch64_NoRegs : CalleeSavedRegs<(add)>;
+
+def CSR_AArch64_RT_MostRegs : CalleeSavedRegs<(add CSR_AArch64_AAPCS,
+ (sequence "X%u", 9, 15))>;
+
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
MachineFrameInfo *MFI = MF.getFrameInfo();
+ CallingConv::ID CC = MF.getFunction()->getCallingConv();
unsigned Count = CSI.size();
+ (void)CC;
// MachO's compact unwind format relies on all registers being stored in
// pairs.
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
+ CC == CallingConv::PreserveMost ||
(Count & 1) == 0) &&
"Odd number of callee-saved regs to spill!");
unsigned Offset = AFI->getCalleeSavedStackSize();
// MachO's compact unwind format relies on all registers being stored in
// adjacent register pairs.
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
+ CC == CallingConv::PreserveMost ||
(RPI.isPaired() &&
((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
RPI.Reg1 + 1 == RPI.Reg2))) &&
return CC_AArch64_GHC;
case CallingConv::C:
case CallingConv::Fast:
+ case CallingConv::PreserveMost:
if (!Subtarget->isTargetDarwin())
return CC_AArch64_AAPCS;
return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS;
}
bool AArch64TargetLowering::IsTailCallConvention(CallingConv::ID CallCC) const {
- return CallCC == CallingConv::Fast;
+ return CallCC == CallingConv::Fast ||
+ CallCC == CallingConv::PreserveMost;
}
/// LowerCall - Lower a call to a callseq_start + CALL + callseq_end chain,
return MF->getInfo<AArch64FunctionInfo>()->isSplitCSR() ?
CSR_AArch64_CXX_TLS_Darwin_PE_SaveList :
CSR_AArch64_CXX_TLS_Darwin_SaveList;
+ if (MF->getFunction()->getCallingConv() == CallingConv::PreserveMost)
+ return CSR_AArch64_RT_MostRegs_SaveList;
else
return CSR_AArch64_AAPCS_SaveList;
}
return CSR_AArch64_AllRegs_RegMask;
if (CC == CallingConv::CXX_FAST_TLS)
return CSR_AArch64_CXX_TLS_Darwin_RegMask;
+ if (CC == CallingConv::PreserveMost)
+ return CSR_AArch64_RT_MostRegs_RegMask;
else
return CSR_AArch64_AAPCS_RegMask;
}
case CallingConv::ARM_APCS:
case CallingConv::GHC:
return CC;
+ case CallingConv::PreserveMost:
+ return CallingConv::PreserveMost;
case CallingConv::ARM_AAPCS_VFP:
return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP;
case CallingConv::C:
return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS);
case CallingConv::GHC:
return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC);
+ case CallingConv::PreserveMost:
+ return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS);
}
}
--- /dev/null
+; RUN: llc < %s -mtriple=arm64-apple-ios-8.0.0 | FileCheck %s
+
+declare void @standard_cc_func()
+declare preserve_mostcc void @preserve_mostcc_func()
+
+; Registers r9-r15 should be saved before the call of a function
+; with a standard calling convention.
+define preserve_mostcc void @preserve_mostcc1() nounwind {
+entry:
+;CHECK-LABEL: preserve_mostcc1
+;CHECK-NOT: stp
+;CHECK-NOT: str
+;CHECK: str x15
+;CHECK-NEXT: stp x14, x13,
+;CHECK-NEXT: stp x12, x11,
+;CHECK-NEXT: stp x10, x9,
+;CHECK: bl _standard_cc_func
+ call void @standard_cc_func()
+;CHECK: ldp x10, x9,
+;CHECK-NEXT: ldp x12, x11,
+;CHECK-NEXT: ldp x14, x13,
+;CHECK-NEXT: ldr x15
+ ret void
+}
+
+; Registers r9-r15 don't need to be saved if one
+; function with preserve_mostcc calling convention calls another
+; function with preserve_mostcc calling convention, because the
+; callee wil save these registers anyways.
+define preserve_mostcc void @preserve_mostcc2() nounwind {
+entry:
+;CHECK-LABEL: preserve_mostcc2
+;CHECK-NOT: x14
+;CHECK: stp x29, x30,
+;CHECK-NOT: x14
+;CHECK: bl _preserve_mostcc_func
+ call preserve_mostcc void @preserve_mostcc_func()
+ ret void
+}
+