Resolve bug 2947: vararg-marked functions must spill registers R3-R79 to stack

so that va_start/va_arg/et.al. will walk arguments correctly for Cell SPU.

N.B.: Because neither clang nor llvm-gcc-4.2 can be built for CellSPU, this is
still unexorcised code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@58415 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Scott Michel 2008-10-30 01:51:48 +00:00
parent a872aae731
commit d976c21241
3 changed files with 79 additions and 116 deletions

View File

@ -188,8 +188,10 @@ namespace {
const MachineOperand &MO = MI->getOperand(OpNo); const MachineOperand &MO = MI->getOperand(OpNo);
assert(MO.isImm() && assert(MO.isImm() &&
"printMemRegImmS10 first operand is not immedate"); "printMemRegImmS10 first operand is not immedate");
printS10ImmOperand(MI, OpNo); int64_t value = int64_t(MI->getOperand(OpNo).getImm());
O << "("; assert((value >= -(1 << (9+4)) && value <= (1 << (9+4)) - 1)
&& "Invalid dform s10 offset argument");
O << value << "(";
printOperand(MI, OpNo+1); printOperand(MI, OpNo+1);
O << ")"; O << ")";
} }

View File

@ -460,10 +460,7 @@ SPUTargetLowering::getTargetNodeName(unsigned Opcode) const
MVT SPUTargetLowering::getSetCCResultType(const SDValue &Op) const { MVT SPUTargetLowering::getSetCCResultType(const SDValue &Op) const {
MVT VT = Op.getValueType(); MVT VT = Op.getValueType();
if (VT.isInteger()) return (VT.isInteger() ? VT : MVT(MVT::i32));
return VT;
else
return MVT::i32;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -926,7 +923,7 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG, int &VarArgsFrameIndex)
MachineFunction &MF = DAG.getMachineFunction(); MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo(); MachineFrameInfo *MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo();
SmallVector<SDValue, 8> ArgValues; SmallVector<SDValue, 48> ArgValues;
SDValue Root = Op.getOperand(0); SDValue Root = Op.getOperand(0);
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0;
@ -942,98 +939,57 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG, int &VarArgsFrameIndex)
// Add DAG nodes to load the arguments or copy them out of registers. // Add DAG nodes to load the arguments or copy them out of registers.
for (unsigned ArgNo = 0, e = Op.getNode()->getNumValues() - 1; for (unsigned ArgNo = 0, e = Op.getNode()->getNumValues() - 1;
ArgNo != e; ++ArgNo) { ArgNo != e; ++ArgNo) {
SDValue ArgVal;
bool needsLoad = false;
MVT ObjectVT = Op.getValue(ArgNo).getValueType(); MVT ObjectVT = Op.getValue(ArgNo).getValueType();
unsigned ObjSize = ObjectVT.getSizeInBits()/8; unsigned ObjSize = ObjectVT.getSizeInBits()/8;
SDValue ArgVal;
switch (ObjectVT.getSimpleVT()) { if (ArgRegIdx < NumArgRegs) {
default: { const TargetRegisterClass *ArgRegClass;
cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
<< ObjectVT.getMVTString()
<< "\n";
abort();
}
case MVT::i8:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R8CRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i8);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::i16:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R16CRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i16);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::i32:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R32CRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i32);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::i64:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R64CRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i64);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::f32:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R32FPRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::f32);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::f64:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::R64FPRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::f64);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
case MVT::v2f64:
case MVT::v4f32:
case MVT::v2i64:
case MVT::v4i32:
case MVT::v8i16:
case MVT::v16i8:
if (!isVarArg && ArgRegIdx < NumArgRegs) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::VECREGRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, ObjectVT);
++ArgRegIdx;
} else {
needsLoad = true;
}
break;
}
// We need to load the argument to a virtual register if we determined above switch (ObjectVT.getSimpleVT()) {
// that we ran out of physical registers of the appropriate type default: {
if (needsLoad) { cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
<< ObjectVT.getMVTString()
<< "\n";
abort();
}
case MVT::i8:
ArgRegClass = &SPU::R8CRegClass;
break;
case MVT::i16:
ArgRegClass = &SPU::R16CRegClass;
break;
case MVT::i32:
ArgRegClass = &SPU::R32CRegClass;
break;
case MVT::i64:
ArgRegClass = &SPU::R64CRegClass;
break;
case MVT::f32:
ArgRegClass = &SPU::R32FPRegClass;
break;
case MVT::f64:
ArgRegClass = &SPU::R64FPRegClass;
break;
case MVT::v2f64:
case MVT::v4f32:
case MVT::v2i64:
case MVT::v4i32:
case MVT::v8i16:
case MVT::v16i8:
ArgRegClass = &SPU::VECREGRegClass;
++ArgRegIdx;
break;
}
unsigned VReg = RegInfo.createVirtualRegister(ArgRegClass);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg);
ArgVal = DAG.getCopyFromReg(Root, VReg, ObjectVT);
++ArgRegIdx;
} else {
// We need to load the argument to a virtual register if we determined
// above that we ran out of physical registers of the appropriate type
// or we're forced to do vararg
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset); int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
SDValue FIN = DAG.getFrameIndex(FI, PtrVT); SDValue FIN = DAG.getFrameIndex(FI, PtrVT);
ArgVal = DAG.getLoad(ObjectVT, Root, FIN, NULL, 0); ArgVal = DAG.getLoad(ObjectVT, Root, FIN, NULL, 0);
@ -1041,30 +997,31 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG, int &VarArgsFrameIndex)
} }
ArgValues.push_back(ArgVal); ArgValues.push_back(ArgVal);
// Update the chain
Root = ArgVal.getOperand(0);
} }
// If the function takes variable number of arguments, make a frame index for // vararg handling:
// the start of the first vararg value... for expansion of llvm.va_start.
if (isVarArg) { if (isVarArg) {
VarArgsFrameIndex = MFI->CreateFixedObject(PtrVT.getSizeInBits()/8, // unsigned int ptr_size = PtrVT.getSizeInBits() / 8;
ArgOffset); // We will spill (79-3)+1 registers to the stack
SDValue FIN = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT); SmallVector<SDValue, 79-3+1> MemOps;
// If this function is vararg, store any remaining integer argument regs to
// their spots on the stack so that they may be loaded by deferencing the // Create the frame slot
// result of va_next.
SmallVector<SDValue, 8> MemOps;
for (; ArgRegIdx != NumArgRegs; ++ArgRegIdx) { for (; ArgRegIdx != NumArgRegs; ++ArgRegIdx) {
unsigned VReg = RegInfo.createVirtualRegister(&SPU::GPRCRegClass); VarArgsFrameIndex = MFI->CreateFixedObject(StackSlotSize, ArgOffset);
RegInfo.addLiveIn(ArgRegs[ArgRegIdx], VReg); SDValue FIN = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT);
SDValue Val = DAG.getCopyFromReg(Root, VReg, PtrVT); SDValue ArgVal = DAG.getRegister(ArgRegs[ArgRegIdx], MVT::v16i8);
SDValue Store = DAG.getStore(Val.getValue(1), Val, FIN, NULL, 0); SDValue Store = DAG.getStore(Root, ArgVal, FIN, NULL, 0);
Root = Store.getOperand(0);
MemOps.push_back(Store); MemOps.push_back(Store);
// Increment the address by four for the next argument to store
SDValue PtrOff = DAG.getConstant(PtrVT.getSizeInBits()/8, PtrVT); // Increment address by stack slot size for the next stored argument
FIN = DAG.getNode(ISD::ADD, PtrOff.getValueType(), FIN, PtrOff); ArgOffset += StackSlotSize;
} }
if (!MemOps.empty()) if (!MemOps.empty())
Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size()); Root = DAG.getNode(ISD::TokenFactor,MVT::Other,&MemOps[0],MemOps.size());
} }
ArgValues.push_back(Root); ArgValues.push_back(Root);
@ -1093,10 +1050,6 @@ SDValue
LowerCALL(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { LowerCALL(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); CallSDNode *TheCall = cast<CallSDNode>(Op.getNode());
SDValue Chain = TheCall->getChain(); SDValue Chain = TheCall->getChain();
#if 0
bool isVarArg = TheCall->isVarArg();
bool isTailCall = TheCall->isTailCall();
#endif
SDValue Callee = TheCall->getCallee(); SDValue Callee = TheCall->getCallee();
unsigned NumOps = TheCall->getNumArgs(); unsigned NumOps = TheCall->getNumArgs();
unsigned StackSlotSize = SPUFrameInfo::stackSlotSize(); unsigned StackSlotSize = SPUFrameInfo::stackSlotSize();

View File

@ -1,6 +1,7 @@
; RUN: llvm-as -o - %s | llc -march=cellspu > %t1.s ; RUN: llvm-as -o - %s | llc -march=cellspu > %t1.s
; RUN: grep brsl %t1.s | count 1 ; RUN: grep brsl %t1.s | count 1
; RUN: grep brasl %t1.s | count 1 ; RUN: grep brasl %t1.s | count 1
; RUN: grep stqd %t1.s | count 81
target datalayout = "E-p:32:32:128-f64:64:128-f32:32:128-i64:32:128-i32:32:128-i16:16:128-i8:8:128-i1:8:128-a0:0:128-v128:128:128-s0:128:128" target datalayout = "E-p:32:32:128-f64:64:128-f32:32:128-i64:32:128-i32:32:128-i16:16:128-i8:8:128-i1:8:128-a0:0:128-v128:128:128-s0:128:128"
target triple = "spu" target triple = "spu"
@ -18,3 +19,10 @@ define i32 @stub_1(i32 %x, float %y) {
entry: entry:
ret i32 0 ret i32 0
} }
; vararg call: ensure that all caller-saved registers are spilled to the
; stack:
define i32 @stub_2(...) {
entry:
ret i32 0
}