[llvm-commits] [llvm] r48209 - in /llvm/trunk/lib/Target/X86: X86FloatingPoint.cpp X86ISelDAGToDAG.cpp X86ISelLowering.cpp X86InstrInfo.td
Chris Lattner
sabre at nondot.org
Mon Mar 10 20:23:40 PDT 2008
Author: lattner
Date: Mon Mar 10 22:23:40 2008
New Revision: 48209
URL: http://llvm.org/viewvc/llvm-project?rev=48209&view=rev
Log:
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.
Modified:
llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp
llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp
llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
llvm/trunk/lib/Target/X86/X86InstrInfo.td
Modified: llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp?rev=48209&r1=48208&r2=48209&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp Mon Mar 10 22:23:40 2008
@@ -75,26 +75,31 @@
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 @@
}
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);
-
- // 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]);
-
- // Emit an fxch to update the runtime processors version of the state
- BuildMI(*MBB, I, TII->get(X86::XCH_F)).addReg(STReg);
- NumFXCH++;
- }
+ 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 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++;
}
void duplicateToTop(unsigned RegNo, unsigned AsReg, MachineInstr *I) {
@@ -268,7 +273,7 @@
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 @@
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;
}
}
Modified: llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp?rev=48209&r1=48208&r2=48209&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp Mon Mar 10 22:23:40 2008
@@ -1168,6 +1168,35 @@
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);
Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=48209&r1=48208&r2=48209&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 10 22:23:40 2008
@@ -853,27 +853,41 @@
// 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());
}
Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.td?rev=48209&r1=48208&r2=48209&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrInfo.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.td Mon Mar 10 22:23:40 2008
@@ -39,7 +39,7 @@
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 @@
// 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 @@
// 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 @@
// Tail call stuff.
-def TAILCALL : I<0, Pseudo, (outs), (ins ),
+def TAILCALL : I<0, Pseudo, (outs), (ins),
"#TAILCALL",
[]>;
More information about the llvm-commits
mailing list