1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 03:33:20 +01:00

Switch PPC over to a call-selection model where the lowering code creates

the copyto/fromregs instead of making the PPCISD::CALL selection code create
them.  This vastly simplifies the selection code, and moves the ABI handling
parts into one place.

llvm-svn: 28346
This commit is contained in:
Chris Lattner 2006-05-17 06:01:33 +00:00
parent 7c87670503
commit 03c70b7f27
3 changed files with 136 additions and 155 deletions

View File

@ -874,129 +874,55 @@ static bool isCallCompatibleAddress(ConstantSDNode *C) {
SDOperand PPCDAGToDAGISel::SelectCALL(SDOperand Op) {
SDNode *N = Op.Val;
SDOperand Chain;
SDOperand Chain, Flag;
Select(Chain, N->getOperand(0));
if (N->getNumOperands() == 3) // input flag
Select(Flag, N->getOperand(2));
unsigned CallOpcode;
std::vector<SDOperand> CallOperands;
std::vector<SDOperand> CallArgs;
if (GlobalAddressSDNode *GASD =
dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
CallOpcode = PPC::BL;
CallOperands.push_back(N->getOperand(1));
CallArgs.push_back(N->getOperand(1));
} else if (ExternalSymbolSDNode *ESSDN =
dyn_cast<ExternalSymbolSDNode>(N->getOperand(1))) {
CallOpcode = PPC::BL;
CallOperands.push_back(N->getOperand(1));
CallArgs.push_back(N->getOperand(1));
} else if (isa<ConstantSDNode>(N->getOperand(1)) &&
isCallCompatibleAddress(cast<ConstantSDNode>(N->getOperand(1)))) {
ConstantSDNode *C = cast<ConstantSDNode>(N->getOperand(1));
CallOpcode = PPC::BLA;
CallOperands.push_back(getI32Imm((int)C->getValue() >> 2));
CallArgs.push_back(getI32Imm((int)C->getValue() >> 2));
} else {
// Copy the callee address into the CTR register.
SDOperand Callee;
Select(Callee, N->getOperand(1));
Chain = SDOperand(CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, Callee,
Chain), 0);
if (Flag.Val)
Chain = SDOperand(CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, MVT::Flag,
Callee, Chain, Flag), 0);
else
Chain = SDOperand(CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, MVT::Flag,
Callee, Chain), 0);
Flag = Chain.getValue(1);
// Copy the callee address into R12 on darwin.
SDOperand R12 = CurDAG->getRegister(PPC::R12, MVT::i32);
Chain = CurDAG->getNode(ISD::CopyToReg, MVT::Other, Chain, R12, Callee);
Chain = CurDAG->getCopyToReg(Chain, PPC::R12, Callee, Flag);
Flag = Chain.getValue(1);
CallOperands.push_back(R12);
CallOpcode = PPC::BCTRL;
}
unsigned GPR_idx = 0, FPR_idx = 0, VR_idx = 0;
static const unsigned GPR[] = {
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
PPC::R7, PPC::R8, PPC::R9, PPC::R10,
};
static const unsigned FPR[] = {
PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
};
static const unsigned VR[] = {
PPC::V2, PPC::V3, PPC::V4, PPC::V5, PPC::V6, PPC::V7, PPC::V8,
PPC::V9, PPC::V10, PPC::V11, PPC::V12, PPC::V13
};
SDOperand InFlag; // Null incoming flag value.
for (unsigned i = 2, e = N->getNumOperands(); i != e; ++i) {
unsigned DestReg = 0;
MVT::ValueType RegTy = N->getOperand(i).getValueType();
if (RegTy == MVT::i32) {
assert(GPR_idx < 8 && "Too many int args");
DestReg = GPR[GPR_idx++];
} else if (MVT::isFloatingPoint(N->getOperand(i).getValueType())) {
assert(FPR_idx < 13 && "Too many fp args");
DestReg = FPR[FPR_idx++];
} else {
assert(MVT::isVector(N->getOperand(i).getValueType()) && "unknown arg!");
assert(VR_idx < 12 && "Too many vector args");
DestReg = VR[VR_idx++];
}
if (N->getOperand(i).getOpcode() != ISD::UNDEF) {
SDOperand Val;
Select(Val, N->getOperand(i));
Chain = CurDAG->getCopyToReg(Chain, DestReg, Val, InFlag);
InFlag = Chain.getValue(1);
CallOperands.push_back(CurDAG->getRegister(DestReg, RegTy));
}
}
// Finally, once everything is in registers to pass to the call, emit the
// call itself.
if (InFlag.Val)
CallOperands.push_back(InFlag); // Strong dep on register copies.
else
CallOperands.push_back(Chain); // Weak dep on whatever occurs before
// Emit the call itself.
CallArgs.push_back(Chain);
if (Flag.Val)
CallArgs.push_back(Flag);
Chain = SDOperand(CurDAG->getTargetNode(CallOpcode, MVT::Other, MVT::Flag,
CallOperands), 0);
std::vector<SDOperand> CallResults;
// If the call has results, copy the values out of the ret val registers.
switch (N->getValueType(0)) {
default: assert(0 && "Unexpected ret value!");
case MVT::Other: break;
case MVT::i32:
if (N->getValueType(1) == MVT::i32) {
Chain = CurDAG->getCopyFromReg(Chain, PPC::R4, MVT::i32,
Chain.getValue(1)).getValue(1);
CallResults.push_back(Chain.getValue(0));
Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
Chain.getValue(2)).getValue(1);
CallResults.push_back(Chain.getValue(0));
} else {
Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
Chain.getValue(1)).getValue(1);
CallResults.push_back(Chain.getValue(0));
}
break;
case MVT::f32:
case MVT::f64:
Chain = CurDAG->getCopyFromReg(Chain, PPC::F1, N->getValueType(0),
Chain.getValue(1)).getValue(1);
CallResults.push_back(Chain.getValue(0));
break;
case MVT::v4f32:
case MVT::v4i32:
case MVT::v8i16:
case MVT::v16i8:
Chain = CurDAG->getCopyFromReg(Chain, PPC::V2, N->getValueType(0),
Chain.getValue(1)).getValue(1);
CallResults.push_back(Chain.getValue(0));
break;
}
CallResults.push_back(Chain);
for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
CodeGenMap[Op.getValue(i)] = CallResults[i];
return CallResults[Op.ResNo];
CallArgs), 0);
CodeGenMap[Op.getValue(0)] = Chain;
CodeGenMap[Op.getValue(1)] = Chain.getValue(1);
return Chain.getValue(Op.ResNo);
}
// Select - Convert the specified operand from a target-independent to a

View File

@ -925,11 +925,25 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
// must be stored to our stack, and loaded into integer regs as well, if
// any integer regs are available for argument passing.
unsigned ArgOffset = 24;
unsigned GPR_remaining = 8;
unsigned FPR_remaining = 13;
unsigned VR_remaining = 12;
unsigned GPR_idx = 0, FPR_idx = 0, VR_idx = 0;
static const unsigned GPR[] = {
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
PPC::R7, PPC::R8, PPC::R9, PPC::R10,
};
static const unsigned FPR[] = {
PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
};
static const unsigned VR[] = {
PPC::V2, PPC::V3, PPC::V4, PPC::V5, PPC::V6, PPC::V7, PPC::V8,
PPC::V9, PPC::V10, PPC::V11, PPC::V12, PPC::V13
};
const unsigned NumGPRs = sizeof(GPR)/sizeof(GPR[0]);
const unsigned NumFPRs = sizeof(FPR)/sizeof(FPR[0]);
const unsigned NumVRs = sizeof( VR)/sizeof( VR[0]);
std::vector<SDOperand> MemOps;
std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
std::vector<SDOperand> MemOpChains;
for (unsigned i = 5, e = Op.getNumOperands(); i != e; ++i) {
SDOperand Arg = Op.getOperand(i);
@ -940,57 +954,51 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
switch (Arg.getValueType()) {
default: assert(0 && "Unexpected ValueType for argument!");
case MVT::i32:
if (GPR_remaining > 0) {
args_to_use.push_back(Arg);
--GPR_remaining;
if (GPR_idx != NumGPRs) {
RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Arg));
} else {
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
Arg, PtrOff, DAG.getSrcValue(NULL)));
}
ArgOffset += 4;
break;
case MVT::f32:
case MVT::f64:
if (FPR_remaining > 0) {
args_to_use.push_back(Arg);
--FPR_remaining;
if (FPR_idx != NumFPRs) {
RegsToPass.push_back(std::make_pair(FPR[FPR_idx++], Arg));
if (isVarArg) {
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
Arg, PtrOff,
DAG.getSrcValue(NULL));
MemOps.push_back(Store);
MemOpChains.push_back(Store);
// Float varargs are always shadowed in available integer registers
if (GPR_remaining > 0) {
if (GPR_idx != NumGPRs) {
SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff,
DAG.getSrcValue(NULL));
MemOps.push_back(Load.getValue(1));
args_to_use.push_back(Load);
--GPR_remaining;
MemOpChains.push_back(Load.getValue(1));
RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Load));
}
if (GPR_remaining > 0 && Arg.getValueType() == MVT::f64) {
if (GPR_idx != NumGPRs && Arg.getValueType() == MVT::f64) {
SDOperand ConstFour = DAG.getConstant(4, PtrOff.getValueType());
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, PtrOff, ConstFour);
SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff,
DAG.getSrcValue(NULL));
MemOps.push_back(Load.getValue(1));
args_to_use.push_back(Load);
--GPR_remaining;
MemOpChains.push_back(Load.getValue(1));
RegsToPass.push_back(std::make_pair(GPR[GPR_idx++], Load));
}
} else {
// If we have any FPRs remaining, we may also have GPRs remaining.
// Args passed in FPRs consume either 1 (f32) or 2 (f64) available
// GPRs.
if (GPR_remaining > 0) {
args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
--GPR_remaining;
}
if (GPR_remaining > 0 && Arg.getValueType() == MVT::f64) {
args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
--GPR_remaining;
}
if (GPR_idx != NumGPRs)
++GPR_idx;
if (GPR_idx != NumGPRs && Arg.getValueType() == MVT::f64)
++GPR_idx;
}
} else {
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
Arg, PtrOff, DAG.getSrcValue(NULL)));
}
ArgOffset += (Arg.getValueType() == MVT::f32) ? 4 : 8;
@ -1000,43 +1008,86 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
case MVT::v8i16:
case MVT::v16i8:
assert(!isVarArg && "Don't support passing vectors to varargs yet!");
assert(VR_remaining &&
assert(VR_idx != NumVRs &&
"Don't support passing more than 12 vector args yet!");
args_to_use.push_back(Arg);
--VR_remaining;
RegsToPass.push_back(std::make_pair(VR[VR_idx++], Arg));
break;
}
}
if (!MemOps.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, MemOps);
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, MemOpChains);
std::vector<MVT::ValueType> RetVals(Op.Val->value_begin(),
Op.Val->value_end());
// Build a sequence of copy-to-reg nodes chained together with token chain
// and flag operands which copy the outgoing args into the appropriate regs.
SDOperand InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
InFlag);
InFlag = Chain.getValue(1);
}
// If the callee is a GlobalAddress node (quite common, every direct call is)
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), Callee.getValueType());
// Create the PPCISD::CALL node itself.
std::vector<MVT::ValueType> NodeTys;
NodeTys.push_back(MVT::Other); // Returns a chain
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
std::vector<SDOperand> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
Ops.insert(Ops.end(), args_to_use.begin(), args_to_use.end());
SDOperand TheCall = DAG.getNode(PPCISD::CALL, RetVals, Ops);
if (InFlag.Val)
Ops.push_back(InFlag);
Chain = DAG.getNode(PPCISD::CALL, NodeTys, Ops);
InFlag = Chain.getValue(1);
std::vector<SDOperand> ResultVals;
NodeTys.clear();
// If the call has results, copy the values out of the ret val registers.
switch (Op.Val->getValueType(0)) {
default: assert(0 && "Unexpected ret value!");
case MVT::Other: break;
case MVT::i32:
if (Op.Val->getValueType(1) == MVT::i32) {
Chain = DAG.getCopyFromReg(Chain, PPC::R4, MVT::i32, InFlag).getValue(1);
ResultVals.push_back(Chain.getValue(0));
Chain = DAG.getCopyFromReg(Chain, PPC::R3, MVT::i32,
Chain.getValue(2)).getValue(1);
ResultVals.push_back(Chain.getValue(0));
NodeTys.push_back(MVT::i32);
} else {
Chain = DAG.getCopyFromReg(Chain, PPC::R3, MVT::i32, InFlag).getValue(1);
ResultVals.push_back(Chain.getValue(0));
}
NodeTys.push_back(MVT::i32);
break;
case MVT::f32:
case MVT::f64:
Chain = DAG.getCopyFromReg(Chain, PPC::F1, Op.Val->getValueType(0),
InFlag).getValue(1);
ResultVals.push_back(Chain.getValue(0));
NodeTys.push_back(Op.Val->getValueType(0));
break;
case MVT::v4f32:
case MVT::v4i32:
case MVT::v8i16:
case MVT::v16i8:
Chain = DAG.getCopyFromReg(Chain, PPC::V2, Op.Val->getValueType(0),
InFlag).getValue(1);
ResultVals.push_back(Chain.getValue(0));
NodeTys.push_back(Op.Val->getValueType(0));
break;
}
Chain = TheCall.getValue(TheCall.Val->getNumValues()-1);
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
DAG.getConstant(NumBytes, MVT::i32));
NodeTys.push_back(MVT::Other);
std::vector<MVT::ValueType> RetVT(Op.Val->value_begin(),
Op.Val->value_end());
Ops.clear();
for (unsigned i = 0, e = TheCall.Val->getNumValues()-1; i != e; ++i)
Ops.push_back(SDOperand(TheCall.Val, i));
Ops.push_back(Chain);
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, RetVT, Ops);
ResultVals.push_back(Chain);
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, ResultVals);
return Res.getValue(Op.ResNo);
}

View File

@ -72,6 +72,10 @@ def PPCstd_32 : SDNode<"PPCISD::STD_32" , SDTStore, [SDNPHasChain]>;
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_PPCCallSeq,[SDNPHasChain]>;
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_PPCCallSeq,[SDNPHasChain]>;
def SDT_PPCCall : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
def call : SDNode<"PPCISD::CALL", SDT_PPCCall,
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
def retflag : SDNode<"PPCISD::RET_FLAG", SDT_PPCRetFlag,
[SDNPHasChain, SDNPOptInFlag]>;
@ -303,11 +307,11 @@ let isCall = 1, noResults = 1, PPC970_Unit = 7,
LR,CTR,
CR0,CR1,CR5,CR6,CR7] in {
// Convenient aliases for call instructions
def BL : IForm<18, 0, 1, (ops calltarget:$func, variable_ops),
def BL : IForm<18, 0, 1, (ops calltarget:$func),
"bl $func", BrB, []>;
def BLA : IForm<18, 1, 1, (ops aaddr:$func, variable_ops),
def BLA : IForm<18, 1, 1, (ops aaddr:$func),
"bla $func", BrB, []>;
def BCTRL : XLForm_2_ext<19, 528, 20, 0, 1, (ops variable_ops), "bctrl", BrB,
def BCTRL : XLForm_2_ext<19, 528, 20, 0, 1, (ops), "bctrl", BrB,
[]>;
}