summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Lytton <robert@xmos.com>2013-08-01 08:18:55 +0000
committerRobert Lytton <robert@xmos.com>2013-08-01 08:18:55 +0000
commitf2617291e31bc93d3dae2c80d45df5dfb9a70ae5 (patch)
treeb8074742e082495c2cc207215a7f271582b43af5
parent98369fb0e72846179814e221d284bcb8b386e599 (diff)
downloadllvm-f2617291e31bc93d3dae2c80d45df5dfb9a70ae5.tar.gz
llvm-f2617291e31bc93d3dae2c80d45df5dfb9a70ae5.tar.bz2
llvm-f2617291e31bc93d3dae2c80d45df5dfb9a70ae5.tar.xz
XCore target: Add byval handling
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187563 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/XCore/XCoreISelLowering.cpp74
-rw-r--r--test/CodeGen/XCore/byVal.ll58
2 files changed, 121 insertions, 11 deletions
diff --git a/lib/Target/XCore/XCoreISelLowering.cpp b/lib/Target/XCore/XCoreISelLowering.cpp
index 21add4de33..1d75a2849e 100644
--- a/lib/Target/XCore/XCoreISelLowering.cpp
+++ b/lib/Target/XCore/XCoreISelLowering.cpp
@@ -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;
}
diff --git a/test/CodeGen/XCore/byVal.ll b/test/CodeGen/XCore/byVal.ll
new file mode 100644
index 0000000000..a5d25d2d95
--- /dev/null
+++ b/test/CodeGen/XCore/byVal.ll
@@ -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
+}