mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-26 14:15:53 +00:00
XCore target: Add byval handling
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187563 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
98369fb0e7
commit
f2617291e3
@ -1031,6 +1031,10 @@ XCoreTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag,
|
||||
// Formal Arguments Calling Convention Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
struct ArgDataPair { SDValue SDV; ISD::ArgFlagsTy Flags; };
|
||||
}
|
||||
|
||||
/// XCore formal arguments implementation
|
||||
SDValue
|
||||
XCoreTargetLowering::LowerFormalArguments(SDValue Chain,
|
||||
@ -1080,11 +1084,22 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
|
||||
unsigned LRSaveSize = StackSlotSize;
|
||||
|
||||
// TODO: need to make copies of any byVal arguments
|
||||
// All getCopyFromReg ops must precede any getMemcpys to prevent the
|
||||
// scheduler clobbering a register before it has been copied.
|
||||
// The stages are:
|
||||
// 1. CopyFromReg (and load) arg & vararg registers.
|
||||
// 2. Chain CopyFromReg nodes into a TokenFactor.
|
||||
// 3. Memcpy 'byVal' args & push final InVals.
|
||||
// 4. Chain mem ops nodes into a TokenFactor.
|
||||
SmallVector<SDValue, 4> CFRegNode;
|
||||
SmallVector<ArgDataPair, 4> ArgData;
|
||||
SmallVector<SDValue, 4> MemOps;
|
||||
|
||||
// 1a. CopyFromReg (and load) arg registers.
|
||||
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
||||
|
||||
CCValAssign &VA = ArgLocs[i];
|
||||
SDValue ArgIn;
|
||||
|
||||
if (VA.isRegLoc()) {
|
||||
// Arguments passed in registers
|
||||
@ -1101,7 +1116,8 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
case MVT::i32:
|
||||
unsigned VReg = RegInfo.createVirtualRegister(&XCore::GRRegsRegClass);
|
||||
RegInfo.addLiveIn(VA.getLocReg(), VReg);
|
||||
InVals.push_back(DAG.getCopyFromReg(Chain, dl, VReg, RegVT));
|
||||
ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
|
||||
CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1));
|
||||
}
|
||||
} else {
|
||||
// sanity check
|
||||
@ -1121,14 +1137,17 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
// Create the SelectionDAG nodes corresponding to a load
|
||||
//from this parameter
|
||||
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
||||
InVals.push_back(DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
|
||||
MachinePointerInfo::getFixedStack(FI),
|
||||
false, false, false, 0));
|
||||
ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
|
||||
MachinePointerInfo::getFixedStack(FI),
|
||||
false, false, false, 0);
|
||||
}
|
||||
const ArgDataPair ADP = { ArgIn, Ins[i].Flags };
|
||||
ArgData.push_back(ADP);
|
||||
}
|
||||
|
||||
// 1b. CopyFromReg vararg registers.
|
||||
if (isVarArg) {
|
||||
/* Argument registers */
|
||||
// Argument registers
|
||||
static const uint16_t ArgRegs[] = {
|
||||
XCore::R0, XCore::R1, XCore::R2, XCore::R3
|
||||
};
|
||||
@ -1136,7 +1155,6 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs,
|
||||
array_lengthof(ArgRegs));
|
||||
if (FirstVAReg < array_lengthof(ArgRegs)) {
|
||||
SmallVector<SDValue, 4> MemOps;
|
||||
int offset = 0;
|
||||
// Save remaining registers, storing higher register numbers at a higher
|
||||
// address
|
||||
@ -1152,14 +1170,12 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
unsigned VReg = RegInfo.createVirtualRegister(&XCore::GRRegsRegClass);
|
||||
RegInfo.addLiveIn(ArgRegs[i], VReg);
|
||||
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
|
||||
CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1));
|
||||
// Move argument from virt reg -> stack
|
||||
SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN,
|
||||
MachinePointerInfo(), false, false, 0);
|
||||
MemOps.push_back(Store);
|
||||
}
|
||||
if (!MemOps.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
||||
&MemOps[0], MemOps.size());
|
||||
} else {
|
||||
// This will point to the next argument passed via stack.
|
||||
XFI->setVarArgsFrameIndex(
|
||||
@ -1168,6 +1184,42 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
|
||||
}
|
||||
}
|
||||
|
||||
// 2. chain CopyFromReg nodes into a TokenFactor.
|
||||
if (!CFRegNode.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &CFRegNode[0],
|
||||
CFRegNode.size());
|
||||
|
||||
// 3. Memcpy 'byVal' args & push final InVals.
|
||||
// Aggregates passed "byVal" need to be copied by the callee.
|
||||
// The callee will use a pointer to this copy, rather than the original
|
||||
// pointer.
|
||||
for (SmallVectorImpl<ArgDataPair>::const_iterator ArgDI = ArgData.begin(),
|
||||
ArgDE = ArgData.end();
|
||||
ArgDI != ArgDE; ++ArgDI) {
|
||||
if (ArgDI->Flags.isByVal() && ArgDI->Flags.getByValSize()) {
|
||||
unsigned Size = ArgDI->Flags.getByValSize();
|
||||
unsigned Align = ArgDI->Flags.getByValAlign();
|
||||
// Create a new object on the stack and copy the pointee into it.
|
||||
int FI = MFI->CreateStackObject(Size, Align, false, false);
|
||||
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
||||
InVals.push_back(FIN);
|
||||
MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV,
|
||||
DAG.getConstant(Size, MVT::i32),
|
||||
Align, false, false,
|
||||
MachinePointerInfo(),
|
||||
MachinePointerInfo()));
|
||||
} else {
|
||||
InVals.push_back(ArgDI->SDV);
|
||||
}
|
||||
}
|
||||
|
||||
// 4, chain mem ops nodes into a TokenFactor.
|
||||
if (!MemOps.empty()) {
|
||||
MemOps.push_back(Chain);
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOps[0],
|
||||
MemOps.size());
|
||||
}
|
||||
|
||||
return Chain;
|
||||
}
|
||||
|
||||
|
58
test/CodeGen/XCore/byVal.ll
Normal file
58
test/CodeGen/XCore/byVal.ll
Normal file
@ -0,0 +1,58 @@
|
||||
; RUN: llc < %s -march=xcore | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: f0Test
|
||||
; CHECK: entsp 1
|
||||
; CHECK: bl f0
|
||||
; CHECK: retsp 1
|
||||
%struct.st0 = type { [0 x i32] }
|
||||
declare void @f0(%struct.st0*) nounwind
|
||||
define void @f0Test(%struct.st0* byval %s0) nounwind {
|
||||
entry:
|
||||
call void @f0(%struct.st0* %s0) nounwind
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f1Test
|
||||
; CHECK: entsp 13
|
||||
; CHECK: stw r4, sp[12]
|
||||
; CHECK: stw r5, sp[11]
|
||||
; CHECK: mov r4, r0
|
||||
; CHECK: ldaw r5, sp[1]
|
||||
; CHECK: ldc r2, 40
|
||||
; CHECK: mov r0, r5
|
||||
; CHECK: bl memcpy
|
||||
; CHECK: mov r0, r5
|
||||
; CHECK: bl f1
|
||||
; CHECK: mov r0, r4
|
||||
; CHECK: ldw r5, sp[11]
|
||||
; CHECK: ldw r4, sp[12]
|
||||
; CHECK: retsp 13
|
||||
%struct.st1 = type { [10 x i32] }
|
||||
declare void @f1(%struct.st1*) nounwind
|
||||
define i32 @f1Test(i32 %i, %struct.st1* byval %s1) nounwind {
|
||||
entry:
|
||||
call void @f1(%struct.st1* %s1) nounwind
|
||||
ret i32 %i
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f2Test
|
||||
; CHECK: extsp 4
|
||||
; CHECK: stw lr, sp[1]
|
||||
; CHECK: stw r2, sp[3]
|
||||
; CHECK: stw r3, sp[4]
|
||||
; CHECK: ldw r0, r0[0]
|
||||
; CHECK: stw r0, sp[2]
|
||||
; CHECK: ldaw r2, sp[2]
|
||||
; CHECK: mov r0, r1
|
||||
; CHECK: mov r1, r2
|
||||
; CHECK: bl f2
|
||||
; CHECK: ldw lr, sp[1]
|
||||
; CHECK: ldaw sp, sp[4]
|
||||
; CHECK: retsp 0
|
||||
%struct.st2 = type { i32 }
|
||||
declare void @f2(i32, %struct.st2*) nounwind
|
||||
define void @f2Test(%struct.st2* byval %s2, i32 %i, ...) nounwind {
|
||||
entry:
|
||||
call void @f2(i32 %i, %struct.st2* %s2)
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user