Change the model for FP Stack return to use fp operands on the

RET instruction instead of using FpSET_ST0_32.  This also generalizes
the code to handling returning of multiple FP results.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48209 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2008-03-11 03:23:40 +00:00
parent c5733ac5d3
commit 447ff68c08
4 changed files with 162 additions and 34 deletions

View File

@ -75,26 +75,31 @@ namespace {
cerr << "\n";
}
private:
/// isStackEmpty - Return true if the FP stack is empty.
bool isStackEmpty() const {
return StackTop == 0;
}
// getSlot - Return the stack slot number a particular register number is
// in...
// in.
unsigned getSlot(unsigned RegNo) const {
assert(RegNo < 8 && "Regno out of range!");
return RegMap[RegNo];
}
// getStackEntry - Return the X86::FP<n> register in register ST(i)
// getStackEntry - Return the X86::FP<n> register in register ST(i).
unsigned getStackEntry(unsigned STi) const {
assert(STi < StackTop && "Access past stack top!");
return Stack[StackTop-1-STi];
}
// getSTReg - Return the X86::ST(i) register which contains the specified
// FP<RegNo> register
// FP<RegNo> register.
unsigned getSTReg(unsigned RegNo) const {
return StackTop - 1 - getSlot(RegNo) + llvm::X86::ST0;
}
// pushReg - Push the specified FP<n> register onto the stack
// pushReg - Push the specified FP<n> register onto the stack.
void pushReg(unsigned Reg) {
assert(Reg < 8 && "Register number out of range!");
assert(StackTop < 8 && "Stack overflow!");
@ -103,22 +108,22 @@ namespace {
}
bool isAtTop(unsigned RegNo) const { return getSlot(RegNo) == StackTop-1; }
void moveToTop(unsigned RegNo, MachineBasicBlock::iterator &I) {
if (!isAtTop(RegNo)) {
unsigned STReg = getSTReg(RegNo);
unsigned RegOnTop = getStackEntry(0);
void moveToTop(unsigned RegNo, MachineBasicBlock::iterator I) {
if (isAtTop(RegNo)) return;
unsigned STReg = getSTReg(RegNo);
unsigned RegOnTop = getStackEntry(0);
// Swap the slots the regs are in
std::swap(RegMap[RegNo], RegMap[RegOnTop]);
// Swap the slots the regs are in.
std::swap(RegMap[RegNo], RegMap[RegOnTop]);
// Swap stack slot contents
assert(RegMap[RegOnTop] < StackTop);
std::swap(Stack[RegMap[RegOnTop]], Stack[StackTop-1]);
// Swap stack slot contents.
assert(RegMap[RegOnTop] < StackTop);
std::swap(Stack[RegMap[RegOnTop]], Stack[StackTop-1]);
// Emit an fxch to update the runtime processors version of the state
BuildMI(*MBB, I, TII->get(X86::XCH_F)).addReg(STReg);
NumFXCH++;
}
// Emit an fxch to update the runtime processors version of the state.
BuildMI(*MBB, I, TII->get(X86::XCH_F)).addReg(STReg);
NumFXCH++;
}
void duplicateToTop(unsigned RegNo, unsigned AsReg, MachineInstr *I) {
@ -268,7 +273,7 @@ bool FPS::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) {
Changed = true;
}
assert(StackTop == 0 && "Stack not empty at end of basic block?");
assert(isStackEmpty() && "Stack not empty at end of basic block?");
return Changed;
}
@ -960,6 +965,83 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
duplicateToTop(SrcReg, DestReg, I);
}
break;
case X86::RET:
case X86::RETI:
// If RET has an FP register use operand, pass the first one in ST(0) and
// the second one in ST(1).
if (isStackEmpty()) return; // Quick check to see if any are possible.
// Find the register operands.
unsigned FirstFPRegOp = ~0U, SecondFPRegOp = ~0U;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &Op = MI->getOperand(i);
if (!Op.isReg() || Op.getReg() < X86::FP0 || Op.getReg() > X86::FP6)
continue;
assert(Op.isUse() && Op.isKill() &&
"Ret only defs operands, and values aren't live beyond it");
if (FirstFPRegOp == ~0U)
FirstFPRegOp = getFPReg(Op);
else {
assert(SecondFPRegOp == ~0U && "More than two fp operands!");
SecondFPRegOp = getFPReg(Op);
}
// Remove the operand so that later passes don't see it.
MI->RemoveOperand(i);
--i, --e;
}
// There are only four possibilities here:
// 1) we are returning a single FP value. In this case, it has to be in
// ST(0) already, so just declare success by removing the value from the
// FP Stack.
if (SecondFPRegOp == ~0U) {
// Assert that the top of stack contains the right FP register.
assert(StackTop == 1 && FirstFPRegOp == getStackEntry(0) &&
"Top of stack not the right register for RET!");
// Ok, everything is good, mark the value as not being on the stack
// anymore so that our assertion about the stack being empty at end of
// block doesn't fire.
StackTop = 0;
return;
}
assert(0 && "TODO: This code should work, but has never been tested."
"Test it when we have multiple FP return values working");
// Otherwise, we are returning two values:
// 2) If returning the same value for both, we only have one thing in the FP
// stack. Consider: RET FP1, FP1
if (StackTop == 1) {
assert(FirstFPRegOp == SecondFPRegOp && FirstFPRegOp == getStackEntry(0)&&
"Stack misconfiguration for RET!");
// Duplicate the TOS so that we return it twice. Just pick some other FPx
// register to hold it.
unsigned NewReg = (FirstFPRegOp+1)%7;
duplicateToTop(FirstFPRegOp, NewReg, MI);
FirstFPRegOp = NewReg;
}
/// Okay we know we have two different FPx operands now:
assert(StackTop == 2 && "Must have two values live!");
/// 3) If SecondFPRegOp is currently in ST(0) and FirstFPRegOp is currently
/// in ST(1). In this case, emit an fxch.
if (getStackEntry(0) == SecondFPRegOp) {
assert(getStackEntry(1) == FirstFPRegOp && "Unknown regs live");
moveToTop(FirstFPRegOp, MI);
}
/// 4) Finally, FirstFPRegOp must be in ST(0) and SecondFPRegOp must be in
/// ST(1). Just remove both from our understanding of the stack and return.
assert(getStackEntry(0) == FirstFPRegOp && "Unknown regs live");
assert(getStackEntry(0) == SecondFPRegOp && "Unknown regs live");
StackTop = 0;
return;
}
}

View File

@ -1168,6 +1168,35 @@ SDNode *X86DAGToDAGISel::Select(SDOperand N) {
case X86ISD::GlobalBaseReg:
return getGlobalBaseReg();
// FIXME: This is a workaround for a tblgen problem: rdar://5791600
case X86ISD::RET_FLAG:
if (ConstantSDNode *Amt = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
if (Amt->getSignExtended() != 0) break;
// Match (X86retflag 0).
SDOperand Chain = N.getOperand(0);
bool HasInFlag = N.getOperand(N.getNumOperands()-1).getValueType()
== MVT::Flag;
SmallVector<SDOperand, 8> Ops0;
AddToISelQueue(Chain);
SDOperand InFlag(0, 0);
if (HasInFlag) {
InFlag = N.getOperand(N.getNumOperands()-1);
AddToISelQueue(InFlag);
}
for (unsigned i = 2, e = N.getNumOperands()-(HasInFlag?1:0); i != e;
++i) {
AddToISelQueue(N.getOperand(i));
Ops0.push_back(N.getOperand(i));
}
Ops0.push_back(Chain);
if (HasInFlag)
Ops0.push_back(InFlag);
return CurDAG->getTargetNode(X86::RET, MVT::Other,
&Ops0[0], Ops0.size());
}
break;
case X86ISD::FP_GET_ST0_ST1: {
SDOperand Chain = N.getOperand(0);
SDOperand InFlag = N.getOperand(1);

View File

@ -853,27 +853,41 @@ SDOperand X86TargetLowering::LowerRET(SDOperand Op, SelectionDAG &DAG) {
// Regular return.
SDOperand Flag;
SmallVector<SDOperand, 6> RetOps;
RetOps.push_back(Chain); // Operand #0 = Chain (updated below)
// Operand #1 = Bytes To Pop
RetOps.push_back(DAG.getConstant(getBytesToPopOnReturn(), MVT::i16));
// Copy the result values into the output registers.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
SDOperand ValToCopy = Op.getOperand(i*2+1);
// If this is a copy from an xmm register to ST(0), use an FPExtend to
// change the value to the FP stack register class.
if (RVLocs[i].getLocReg() == X86::ST0 &&
isScalarFPTypeInSSEReg(RVLocs[i].getValVT()))
ValToCopy = DAG.getNode(ISD::FP_EXTEND, MVT::f80, ValToCopy);
// Returns in ST0/ST1 are handled specially: these are pushed as operands to
// the RET instruction and handled by the FP Stackifier.
if (RVLocs[i].getLocReg() == X86::ST0 ||
RVLocs[i].getLocReg() == X86::ST1) {
// If this is a copy from an xmm register to ST(0), use an FPExtend to
// change the value to the FP stack register class.
if (isScalarFPTypeInSSEReg(RVLocs[i].getValVT()))
ValToCopy = DAG.getNode(ISD::FP_EXTEND, MVT::f80, ValToCopy);
RetOps.push_back(ValToCopy);
// Don't emit a copytoreg.
continue;
}
Chain = DAG.getCopyToReg(Chain, VA.getLocReg(), ValToCopy, Flag);
Flag = Chain.getValue(1);
}
SDOperand BytesToPop = DAG.getConstant(getBytesToPopOnReturn(), MVT::i16);
RetOps[0] = Chain; // Update chain.
// Add the flag if we have it.
if (Flag.Val)
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Chain, BytesToPop, Flag);
else
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Chain, BytesToPop);
RetOps.push_back(Flag);
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, &RetOps[0], RetOps.size());
}

View File

@ -39,7 +39,7 @@ def SDTX86cas : SDTypeProfile<0, 3, [SDTCisPtrTy<0>, SDTCisInt<1>,
SDTCisVT<2, i8>]>;
def SDTX86cas8 : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
def SDTX86Ret : SDTypeProfile<0, 1, [SDTCisVT<0, i16>]>;
def SDTX86Ret : SDTypeProfile<0, -1, [SDTCisVT<0, i16>]>;
def SDT_X86CallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
def SDT_X86CallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
@ -269,8 +269,8 @@ def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{
// ADJCALLSTACKDOWN/UP implicitly use/def ESP because they may be expanded into
// a stack adjustment and the codegen must know that they may modify the stack
// pointer before prolog-epilog rewriting occurs.
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become sub / add
// which can clobber EFLAGS.
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
// sub / add which can clobber EFLAGS.
let Defs = [ESP, EFLAGS], Uses = [ESP] in {
def ADJCALLSTACKDOWN : I<0, Pseudo, (outs), (ins i32imm:$amt),
"#ADJCALLSTACKDOWN",
@ -306,9 +306,12 @@ let neverHasSideEffects = 1, isNotDuplicable = 1 in
// Return instructions.
let isTerminator = 1, isReturn = 1, isBarrier = 1,
hasCtrlDep = 1 in {
def RET : I<0xC3, RawFrm, (outs), (ins), "ret", [(X86retflag 0)]>;
def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt), "ret\t$amt",
hasCtrlDep = 1, FPForm = SpecialFP, FPFormBits = SpecialFP.Value in {
def RET : I <0xC3, RawFrm, (outs), (ins variable_ops),
"ret",
[/*(X86retflag 0)*/ /*FIXME: Disabled: rdar://5791600*/]>;
def RETI : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
"ret\t$amt",
[(X86retflag imm:$amt)]>;
}
@ -384,7 +387,7 @@ let isCall = 1 in
// Tail call stuff.
def TAILCALL : I<0, Pseudo, (outs), (ins ),
def TAILCALL : I<0, Pseudo, (outs), (ins),
"#TAILCALL",
[]>;