mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-14 15:28:20 +00:00
[arm-fast-isel] Add support for vararg function calls.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160500 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -193,18 +193,21 @@ class ARMFastISel : public FastISel {
|
|||||||
|
|
||||||
// Call handling routines.
|
// Call handling routines.
|
||||||
private:
|
private:
|
||||||
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return);
|
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC,
|
||||||
|
bool Return,
|
||||||
|
bool isVarArg);
|
||||||
bool ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
bool ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
||||||
SmallVectorImpl<unsigned> &ArgRegs,
|
SmallVectorImpl<unsigned> &ArgRegs,
|
||||||
SmallVectorImpl<MVT> &ArgVTs,
|
SmallVectorImpl<MVT> &ArgVTs,
|
||||||
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
||||||
SmallVectorImpl<unsigned> &RegArgs,
|
SmallVectorImpl<unsigned> &RegArgs,
|
||||||
CallingConv::ID CC,
|
CallingConv::ID CC,
|
||||||
unsigned &NumBytes);
|
unsigned &NumBytes,
|
||||||
|
bool isVarArg);
|
||||||
unsigned getLibcallReg(const Twine &Name);
|
unsigned getLibcallReg(const Twine &Name);
|
||||||
bool FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
bool FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
||||||
const Instruction *I, CallingConv::ID CC,
|
const Instruction *I, CallingConv::ID CC,
|
||||||
unsigned &NumBytes);
|
unsigned &NumBytes, bool isVarArg);
|
||||||
bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call);
|
bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call);
|
||||||
|
|
||||||
// OptionalDef handling routines.
|
// OptionalDef handling routines.
|
||||||
@@ -1807,10 +1810,11 @@ bool ARMFastISel::SelectBinaryFPOp(const Instruction *I, unsigned ISDOpcode) {
|
|||||||
|
|
||||||
// Call Handling Code
|
// Call Handling Code
|
||||||
|
|
||||||
// This is largely taken directly from CCAssignFnForNode - we don't support
|
// This is largely taken directly from CCAssignFnForNode
|
||||||
// varargs in FastISel so that part has been removed.
|
|
||||||
// TODO: We may not support all of this.
|
// TODO: We may not support all of this.
|
||||||
CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return) {
|
CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC,
|
||||||
|
bool Return,
|
||||||
|
bool isVarArg) {
|
||||||
switch (CC) {
|
switch (CC) {
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Unsupported calling convention");
|
llvm_unreachable("Unsupported calling convention");
|
||||||
@@ -1823,14 +1827,17 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return) {
|
|||||||
// Use target triple & subtarget features to do actual dispatch.
|
// Use target triple & subtarget features to do actual dispatch.
|
||||||
if (Subtarget->isAAPCS_ABI()) {
|
if (Subtarget->isAAPCS_ABI()) {
|
||||||
if (Subtarget->hasVFP2() &&
|
if (Subtarget->hasVFP2() &&
|
||||||
TM.Options.FloatABIType == FloatABI::Hard)
|
TM.Options.FloatABIType == FloatABI::Hard && !isVarArg)
|
||||||
return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
|
return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
|
||||||
else
|
else
|
||||||
return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS);
|
return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS);
|
||||||
} else
|
} else
|
||||||
return (Return ? RetCC_ARM_APCS: CC_ARM_APCS);
|
return (Return ? RetCC_ARM_APCS: CC_ARM_APCS);
|
||||||
case CallingConv::ARM_AAPCS_VFP:
|
case CallingConv::ARM_AAPCS_VFP:
|
||||||
return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
|
if (!isVarArg)
|
||||||
|
return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
|
||||||
|
// Fall through to soft float variant, variadic functions don't
|
||||||
|
// use hard floating point ABI.
|
||||||
case CallingConv::ARM_AAPCS:
|
case CallingConv::ARM_AAPCS:
|
||||||
return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS);
|
return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS);
|
||||||
case CallingConv::ARM_APCS:
|
case CallingConv::ARM_APCS:
|
||||||
@@ -1844,10 +1851,12 @@ bool ARMFastISel::ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
|||||||
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
||||||
SmallVectorImpl<unsigned> &RegArgs,
|
SmallVectorImpl<unsigned> &RegArgs,
|
||||||
CallingConv::ID CC,
|
CallingConv::ID CC,
|
||||||
unsigned &NumBytes) {
|
unsigned &NumBytes,
|
||||||
|
bool isVarArg) {
|
||||||
SmallVector<CCValAssign, 16> ArgLocs;
|
SmallVector<CCValAssign, 16> ArgLocs;
|
||||||
CCState CCInfo(CC, false, *FuncInfo.MF, TM, ArgLocs, *Context);
|
CCState CCInfo(CC, isVarArg, *FuncInfo.MF, TM, ArgLocs, *Context);
|
||||||
CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false));
|
CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags,
|
||||||
|
CCAssignFnForCall(CC, false, isVarArg));
|
||||||
|
|
||||||
// Check that we can handle all of the arguments. If we can't, then bail out
|
// Check that we can handle all of the arguments. If we can't, then bail out
|
||||||
// now before we add code to the MBB.
|
// now before we add code to the MBB.
|
||||||
@@ -1979,7 +1988,7 @@ bool ARMFastISel::ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
|||||||
|
|
||||||
bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
||||||
const Instruction *I, CallingConv::ID CC,
|
const Instruction *I, CallingConv::ID CC,
|
||||||
unsigned &NumBytes) {
|
unsigned &NumBytes, bool isVarArg) {
|
||||||
// Issue CALLSEQ_END
|
// Issue CALLSEQ_END
|
||||||
unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
|
unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
|
||||||
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,
|
||||||
@@ -1989,8 +1998,8 @@ bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
|||||||
// Now the return value.
|
// Now the return value.
|
||||||
if (RetVT != MVT::isVoid) {
|
if (RetVT != MVT::isVoid) {
|
||||||
SmallVector<CCValAssign, 16> RVLocs;
|
SmallVector<CCValAssign, 16> RVLocs;
|
||||||
CCState CCInfo(CC, false, *FuncInfo.MF, TM, RVLocs, *Context);
|
CCState CCInfo(CC, isVarArg, *FuncInfo.MF, TM, RVLocs, *Context);
|
||||||
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true));
|
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, isVarArg));
|
||||||
|
|
||||||
// Copy all of the result registers out of their specified physreg.
|
// Copy all of the result registers out of their specified physreg.
|
||||||
if (RVLocs.size() == 2 && RetVT == MVT::f64) {
|
if (RVLocs.size() == 2 && RetVT == MVT::f64) {
|
||||||
@@ -2039,9 +2048,6 @@ bool ARMFastISel::SelectRet(const Instruction *I) {
|
|||||||
if (!FuncInfo.CanLowerReturn)
|
if (!FuncInfo.CanLowerReturn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (F.isVarArg())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CallingConv::ID CC = F.getCallingConv();
|
CallingConv::ID CC = F.getCallingConv();
|
||||||
if (Ret->getNumOperands() > 0) {
|
if (Ret->getNumOperands() > 0) {
|
||||||
SmallVector<ISD::OutputArg, 4> Outs;
|
SmallVector<ISD::OutputArg, 4> Outs;
|
||||||
@@ -2051,7 +2057,8 @@ bool ARMFastISel::SelectRet(const Instruction *I) {
|
|||||||
// Analyze operands of the call, assigning locations to each operand.
|
// Analyze operands of the call, assigning locations to each operand.
|
||||||
SmallVector<CCValAssign, 16> ValLocs;
|
SmallVector<CCValAssign, 16> ValLocs;
|
||||||
CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, TM, ValLocs,I->getContext());
|
CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, TM, ValLocs,I->getContext());
|
||||||
CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC, true /* is Ret */));
|
CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC, true /* is Ret */,
|
||||||
|
F.isVarArg()));
|
||||||
|
|
||||||
const Value *RV = Ret->getOperand(0);
|
const Value *RV = Ret->getOperand(0);
|
||||||
unsigned Reg = getRegForValue(RV);
|
unsigned Reg = getRegForValue(RV);
|
||||||
@@ -2143,7 +2150,7 @@ bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) {
|
|||||||
if (RetVT != MVT::isVoid && RetVT != MVT::i32) {
|
if (RetVT != MVT::isVoid && RetVT != MVT::i32) {
|
||||||
SmallVector<CCValAssign, 16> RVLocs;
|
SmallVector<CCValAssign, 16> RVLocs;
|
||||||
CCState CCInfo(CC, false, *FuncInfo.MF, TM, RVLocs, *Context);
|
CCState CCInfo(CC, false, *FuncInfo.MF, TM, RVLocs, *Context);
|
||||||
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true));
|
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, false));
|
||||||
if (RVLocs.size() >= 2 && RetVT != MVT::f64)
|
if (RVLocs.size() >= 2 && RetVT != MVT::f64)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2179,7 +2186,8 @@ bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) {
|
|||||||
// Handle the arguments now that we've gotten them.
|
// Handle the arguments now that we've gotten them.
|
||||||
SmallVector<unsigned, 4> RegArgs;
|
SmallVector<unsigned, 4> RegArgs;
|
||||||
unsigned NumBytes;
|
unsigned NumBytes;
|
||||||
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes))
|
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags,
|
||||||
|
RegArgs, CC, NumBytes, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned CalleeReg = 0;
|
unsigned CalleeReg = 0;
|
||||||
@@ -2218,7 +2226,7 @@ bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) {
|
|||||||
|
|
||||||
// Finish off the call including any return values.
|
// Finish off the call including any return values.
|
||||||
SmallVector<unsigned, 4> UsedRegs;
|
SmallVector<unsigned, 4> UsedRegs;
|
||||||
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false;
|
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, false)) return false;
|
||||||
|
|
||||||
// Set all unused physreg defs as dead.
|
// Set all unused physreg defs as dead.
|
||||||
static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);
|
static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);
|
||||||
@@ -2240,11 +2248,9 @@ bool ARMFastISel::SelectCall(const Instruction *I,
|
|||||||
|
|
||||||
// TODO: Avoid some calling conventions?
|
// TODO: Avoid some calling conventions?
|
||||||
|
|
||||||
// Let SDISel handle vararg functions.
|
|
||||||
PointerType *PT = cast<PointerType>(CS.getCalledValue()->getType());
|
PointerType *PT = cast<PointerType>(CS.getCalledValue()->getType());
|
||||||
FunctionType *FTy = cast<FunctionType>(PT->getElementType());
|
FunctionType *FTy = cast<FunctionType>(PT->getElementType());
|
||||||
if (FTy->isVarArg())
|
bool isVarArg = FTy->isVarArg();
|
||||||
return false;
|
|
||||||
|
|
||||||
// Handle *simple* calls for now.
|
// Handle *simple* calls for now.
|
||||||
Type *RetTy = I->getType();
|
Type *RetTy = I->getType();
|
||||||
@@ -2259,8 +2265,8 @@ bool ARMFastISel::SelectCall(const Instruction *I,
|
|||||||
if (RetVT != MVT::isVoid && RetVT != MVT::i1 && RetVT != MVT::i8 &&
|
if (RetVT != MVT::isVoid && RetVT != MVT::i1 && RetVT != MVT::i8 &&
|
||||||
RetVT != MVT::i16 && RetVT != MVT::i32) {
|
RetVT != MVT::i16 && RetVT != MVT::i32) {
|
||||||
SmallVector<CCValAssign, 16> RVLocs;
|
SmallVector<CCValAssign, 16> RVLocs;
|
||||||
CCState CCInfo(CC, false, *FuncInfo.MF, TM, RVLocs, *Context);
|
CCState CCInfo(CC, isVarArg, *FuncInfo.MF, TM, RVLocs, *Context);
|
||||||
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true));
|
CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, isVarArg));
|
||||||
if (RVLocs.size() >= 2 && RetVT != MVT::f64)
|
if (RVLocs.size() >= 2 && RetVT != MVT::f64)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2318,7 +2324,8 @@ bool ARMFastISel::SelectCall(const Instruction *I,
|
|||||||
// Handle the arguments now that we've gotten them.
|
// Handle the arguments now that we've gotten them.
|
||||||
SmallVector<unsigned, 4> RegArgs;
|
SmallVector<unsigned, 4> RegArgs;
|
||||||
unsigned NumBytes;
|
unsigned NumBytes;
|
||||||
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes))
|
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags,
|
||||||
|
RegArgs, CC, NumBytes, isVarArg))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool UseReg = false;
|
bool UseReg = false;
|
||||||
@@ -2370,7 +2377,8 @@ bool ARMFastISel::SelectCall(const Instruction *I,
|
|||||||
|
|
||||||
// Finish off the call including any return values.
|
// Finish off the call including any return values.
|
||||||
SmallVector<unsigned, 4> UsedRegs;
|
SmallVector<unsigned, 4> UsedRegs;
|
||||||
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false;
|
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, isVarArg))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Set all unused physreg defs as dead.
|
// Set all unused physreg defs as dead.
|
||||||
static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);
|
static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);
|
||||||
|
@@ -178,3 +178,46 @@ entry:
|
|||||||
%tmp1 = udiv i32 %a, %b ; <i32> [#uses=1]
|
%tmp1 = udiv i32 %a, %b ; <i32> [#uses=1]
|
||||||
ret i32 %tmp1
|
ret i32 %tmp1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i32 @VarArg() nounwind {
|
||||||
|
entry:
|
||||||
|
%i = alloca i32, align 4
|
||||||
|
%j = alloca i32, align 4
|
||||||
|
%k = alloca i32, align 4
|
||||||
|
%m = alloca i32, align 4
|
||||||
|
%n = alloca i32, align 4
|
||||||
|
%tmp = alloca i32, align 4
|
||||||
|
%0 = load i32* %i, align 4
|
||||||
|
%1 = load i32* %j, align 4
|
||||||
|
%2 = load i32* %k, align 4
|
||||||
|
%3 = load i32* %m, align 4
|
||||||
|
%4 = load i32* %n, align 4
|
||||||
|
; ARM: VarArg
|
||||||
|
; ARM: mov r7, sp
|
||||||
|
; ARM: movw r0, #5
|
||||||
|
; ARM: ldr r1, [r7, #-4]
|
||||||
|
; ARM: ldr r2, [r7, #-8]
|
||||||
|
; ARM: ldr r3, [r7, #-12]
|
||||||
|
; ARM: ldr r9, [sp, #16]
|
||||||
|
; ARM: ldr r12, [sp, #12]
|
||||||
|
; ARM: str r9, [sp]
|
||||||
|
; ARM: str r12, [sp, #4]
|
||||||
|
; ARM: bl _CallVariadic
|
||||||
|
; THUMB: mov r7, sp
|
||||||
|
; THUMB: movs r0, #5
|
||||||
|
; THUMB: movt r0, #0
|
||||||
|
; THUMB: ldr r1, [sp, #28]
|
||||||
|
; THUMB: ldr r2, [sp, #24]
|
||||||
|
; THUMB: ldr r3, [sp, #20]
|
||||||
|
; THUMB: ldr.w r9, [sp, #16]
|
||||||
|
; THUMB: ldr.w r12, [sp, #12]
|
||||||
|
; THUMB: str.w r9, [sp]
|
||||||
|
; THUMB: str.w r12, [sp, #4]
|
||||||
|
; THUMB: bl _CallVariadic
|
||||||
|
%call = call i32 (i32, ...)* @CallVariadic(i32 5, i32 %0, i32 %1, i32 %2, i32 %3, i32 %4)
|
||||||
|
store i32 %call, i32* %tmp, align 4
|
||||||
|
%5 = load i32* %tmp, align 4
|
||||||
|
ret i32 %5
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @CallVariadic(i32, ...)
|
||||||
|
@@ -3,17 +3,18 @@ target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:64-
|
|||||||
target triple = "thumbv7-apple-ios0.0.0"
|
target triple = "thumbv7-apple-ios0.0.0"
|
||||||
|
|
||||||
; This test case would clobber the outgoing call arguments by writing to the
|
; This test case would clobber the outgoing call arguments by writing to the
|
||||||
; emergency spill slot at [sp, #4] without adjusting the stack pointer first.
|
; emergency spill slots at [sp, #4] or [sp, #8] without adjusting the stack
|
||||||
|
; pointer first.
|
||||||
|
|
||||||
; CHECK: main
|
; CHECK: main
|
||||||
; CHECK: vmov.f64
|
; CHECK: vmov.f64
|
||||||
; Adjust SP for the large call
|
; Adjust SP for the large call
|
||||||
; CHECK: sub sp,
|
; CHECK: sub sp,
|
||||||
; CHECK: mov [[FR:r[0-9]+]], sp
|
; Store to call frame + #8
|
||||||
; Store to call frame + #4
|
; CHECK: vstr{{.*\[}}sp, #8]
|
||||||
; CHECK: str{{.*\[}}[[FR]], #4]
|
|
||||||
; Don't clobber that store until the call.
|
; Don't clobber that store until the call.
|
||||||
; CHECK-NOT: [sp, #4]
|
; CHECK-NOT: [sp, #4]
|
||||||
|
; CHECK-NOT: [sp, #8]
|
||||||
; CHECK: variadic
|
; CHECK: variadic
|
||||||
|
|
||||||
define i32 @main() ssp {
|
define i32 @main() ssp {
|
||||||
|
Reference in New Issue
Block a user