diff options
author | Chris Lattner <sabre@nondot.org> | 2008-03-11 03:23:40 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2008-03-11 03:23:40 +0000 |
commit | b56cc3452747982af616484b2960784c68d54227 (patch) | |
tree | 08467f93f493ed3754b0af58a11729d25d9c38a1 /lib/Target | |
parent | 92d5128d2864330cd5dce9658f59c5aac983ddcb (diff) | |
download | external_llvm-b56cc3452747982af616484b2960784c68d54227.zip external_llvm-b56cc3452747982af616484b2960784c68d54227.tar.gz external_llvm-b56cc3452747982af616484b2960784c68d54227.tar.bz2 |
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
Diffstat (limited to 'lib/Target')
-rw-r--r-- | lib/Target/X86/X86FloatingPoint.cpp | 118 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelDAGToDAG.cpp | 29 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelLowering.cpp | 32 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.td | 17 |
4 files changed, 162 insertions, 34 deletions
diff --git a/lib/Target/X86/X86FloatingPoint.cpp b/lib/Target/X86/X86FloatingPoint.cpp index fa1b0eb..6ee79c1 100644 --- a/lib/Target/X86/X86FloatingPoint.cpp +++ b/lib/Target/X86/X86FloatingPoint.cpp @@ -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; } } diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index a4da541..ea1bed1 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -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); diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 179f600..d603e1b 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -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()); } diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 223889c..e32fb9c 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -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", []>; |