Add support for a preserve_most calling convention to the AArch64 backend.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263092 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Roman Levenstein 2016-03-10 04:35:09 +00:00
parent d449fa84ed
commit c461035332
6 changed files with 59 additions and 1 deletions

View File

@ -310,3 +310,7 @@ def CSR_AArch64_AllRegs
(sequence "Q%u", 0, 31))>; (sequence "Q%u", 0, 31))>;
def CSR_AArch64_NoRegs : CalleeSavedRegs<(add)>; def CSR_AArch64_NoRegs : CalleeSavedRegs<(add)>;
def CSR_AArch64_RT_MostRegs : CalleeSavedRegs<(add CSR_AArch64_AAPCS,
(sequence "X%u", 9, 15))>;

View File

@ -723,10 +723,13 @@ static void computeCalleeSaveRegisterPairs(
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>(); AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
MachineFrameInfo *MFI = MF.getFrameInfo(); MachineFrameInfo *MFI = MF.getFrameInfo();
CallingConv::ID CC = MF.getFunction()->getCallingConv();
unsigned Count = CSI.size(); unsigned Count = CSI.size();
(void)CC;
// MachO's compact unwind format relies on all registers being stored in // MachO's compact unwind format relies on all registers being stored in
// pairs. // pairs.
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() || assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
CC == CallingConv::PreserveMost ||
(Count & 1) == 0) && (Count & 1) == 0) &&
"Odd number of callee-saved regs to spill!"); "Odd number of callee-saved regs to spill!");
unsigned Offset = AFI->getCalleeSavedStackSize(); unsigned Offset = AFI->getCalleeSavedStackSize();
@ -760,6 +763,7 @@ static void computeCalleeSaveRegisterPairs(
// MachO's compact unwind format relies on all registers being stored in // MachO's compact unwind format relies on all registers being stored in
// adjacent register pairs. // adjacent register pairs.
assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() || assert((!MF.getSubtarget<AArch64Subtarget>().isTargetMachO() ||
CC == CallingConv::PreserveMost ||
(RPI.isPaired() && (RPI.isPaired() &&
((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) || ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) ||
RPI.Reg1 + 1 == RPI.Reg2))) && RPI.Reg1 + 1 == RPI.Reg2))) &&

View File

@ -2455,6 +2455,7 @@ CCAssignFn *AArch64TargetLowering::CCAssignFnForCall(CallingConv::ID CC,
return CC_AArch64_GHC; return CC_AArch64_GHC;
case CallingConv::C: case CallingConv::C:
case CallingConv::Fast: case CallingConv::Fast:
case CallingConv::PreserveMost:
if (!Subtarget->isTargetDarwin()) if (!Subtarget->isTargetDarwin())
return CC_AArch64_AAPCS; return CC_AArch64_AAPCS;
return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS; return IsVarArg ? CC_AArch64_DarwinPCS_VarArg : CC_AArch64_DarwinPCS;
@ -2942,7 +2943,8 @@ bool AArch64TargetLowering::DoesCalleeRestoreStack(CallingConv::ID CallCC,
} }
bool AArch64TargetLowering::IsTailCallConvention(CallingConv::ID CallCC) const { 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, /// LowerCall - Lower a call to a callseq_start + CALL + callseq_end chain,

View File

@ -51,6 +51,8 @@ AArch64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
return MF->getInfo<AArch64FunctionInfo>()->isSplitCSR() ? return MF->getInfo<AArch64FunctionInfo>()->isSplitCSR() ?
CSR_AArch64_CXX_TLS_Darwin_PE_SaveList : CSR_AArch64_CXX_TLS_Darwin_PE_SaveList :
CSR_AArch64_CXX_TLS_Darwin_SaveList; CSR_AArch64_CXX_TLS_Darwin_SaveList;
if (MF->getFunction()->getCallingConv() == CallingConv::PreserveMost)
return CSR_AArch64_RT_MostRegs_SaveList;
else else
return CSR_AArch64_AAPCS_SaveList; return CSR_AArch64_AAPCS_SaveList;
} }
@ -74,6 +76,8 @@ AArch64RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
return CSR_AArch64_AllRegs_RegMask; return CSR_AArch64_AllRegs_RegMask;
if (CC == CallingConv::CXX_FAST_TLS) if (CC == CallingConv::CXX_FAST_TLS)
return CSR_AArch64_CXX_TLS_Darwin_RegMask; return CSR_AArch64_CXX_TLS_Darwin_RegMask;
if (CC == CallingConv::PreserveMost)
return CSR_AArch64_RT_MostRegs_RegMask;
else else
return CSR_AArch64_AAPCS_RegMask; return CSR_AArch64_AAPCS_RegMask;
} }

View File

@ -1378,6 +1378,8 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
case CallingConv::ARM_APCS: case CallingConv::ARM_APCS:
case CallingConv::GHC: case CallingConv::GHC:
return CC; return CC;
case CallingConv::PreserveMost:
return CallingConv::PreserveMost;
case CallingConv::ARM_AAPCS_VFP: case CallingConv::ARM_AAPCS_VFP:
return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP; return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP;
case CallingConv::C: case CallingConv::C:
@ -1420,6 +1422,8 @@ CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC,
return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS);
case CallingConv::GHC: case CallingConv::GHC:
return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC); return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC);
case CallingConv::PreserveMost:
return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS);
} }
} }

View File

@ -0,0 +1,40 @@
; 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
}