mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-08 03:30:22 +00:00
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:
parent
c5733ac5d3
commit
447ff68c08
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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",
|
||||
[]>;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user