Add support for calls that return two FP values in

ST(0)/ST(1).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48634 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2008-03-21 06:38:26 +00:00
parent ae60ddc22a
commit 24e0a546b4
4 changed files with 91 additions and 5 deletions

View File

@ -933,6 +933,42 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
assert(StackTop == 0 && "Stack should be empty after a call!");
pushReg(getFPReg(MI->getOperand(0)));
break;
case X86::FpGET_ST1_32:// Appears immediately after a call returning FP type!
case X86::FpGET_ST1_64:// Appears immediately after a call returning FP type!
case X86::FpGET_ST1_80:{// Appears immediately after a call returning FP type!
// FpGET_ST1 should occur right after a FpGET_ST0 for a call or inline asm.
// The pattern we expect is:
// CALL
// FP1 = FpGET_ST0
// FP4 = FpGET_ST1
//
// At this point, we've pushed FP1 on the top of stack, so it should be
// present if it isn't dead. If it was dead, we already emitted a pop to
// remove it from the stack and StackTop = 0.
// Push FP4 as top of stack next.
pushReg(getFPReg(MI->getOperand(0)));
// If StackTop was 0 before we pushed our operand, then ST(0) must have been
// dead. In this case, the ST(1) value is the only thing that is live, so
// it should be on the TOS (after the pop that was emitted) and is. Just
// continue in this case.
if (StackTop == 1)
break;
// Because pushReg just pushed ST(1) as TOS, we now have to swap the two top
// elements so that our accounting is correct.
unsigned RegOnTop = getStackEntry(0);
unsigned RegNo = getStackEntry(1);
// 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]);
break;
}
case X86::FpGET_ST0_ST1:
assert(StackTop == 0 && "Stack should be empty after a call!");
pushReg(getFPReg(MI->getOperand(0)));

View File

@ -136,6 +136,15 @@ def FpGET_ST0_32 : FpI_<(outs RFP32:$dst), (ins), SpecialFP, []>; // FPR = ST(0)
def FpGET_ST0_64 : FpI_<(outs RFP64:$dst), (ins), SpecialFP, []>; // FPR = ST(0)
def FpGET_ST0_80 : FpI_<(outs RFP80:$dst), (ins), SpecialFP, []>; // FPR = ST(0)
// FpGET_ST1* should only be issued *after* an FpGET_ST0* has been issued when
// there are two values live out on the stack from a call or inlineasm. This
// magic is handled by the stackifier. It is not valid to emit FpGET_ST1* and
// then FpGET_ST0*. In addition, it is invalid for any FP-using operations to
// occur between them.
def FpGET_ST1_32 : FpI_<(outs RFP32:$dst), (ins), SpecialFP, []>; // FPR = ST(1)
def FpGET_ST1_64 : FpI_<(outs RFP64:$dst), (ins), SpecialFP, []>; // FPR = ST(1)
def FpGET_ST1_80 : FpI_<(outs RFP80:$dst), (ins), SpecialFP, []>; // FPR = ST(1)
def FpGET_ST0_ST1 : FpI_<(outs RFP80:$dst1, RFP80:$dst2), (ins), SpecialFP,
[]>; // FPR = ST(0), FPR = ST(1)

View File

@ -1487,16 +1487,18 @@ void X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
// Moving from ST(0) turns into FpGET_ST0_32 etc.
if (SrcRC == &X86::RSTRegClass) {
// Copying from ST(0). FIXME: handle ST(1) also
assert(SrcReg == X86::ST0 && "Can only copy from TOS right now");
// Copying from ST(0)/ST(1).
assert((SrcReg == X86::ST0 || SrcReg == X86::ST1) &&
"Can only copy from ST(0)/ST(1) right now");
bool isST0 = SrcReg == X86::ST0;
unsigned Opc;
if (DestRC == &X86::RFP32RegClass)
Opc = X86::FpGET_ST0_32;
Opc = isST0 ? X86::FpGET_ST0_32 : X86::FpGET_ST1_32;
else if (DestRC == &X86::RFP64RegClass)
Opc = X86::FpGET_ST0_64;
Opc = isST0 ? X86::FpGET_ST0_64 : X86::FpGET_ST1_64;
else {
assert(DestRC == &X86::RFP80RegClass);
Opc = X86::FpGET_ST0_80;
Opc = isST0 ? X86::FpGET_ST0_80 : X86::FpGET_ST1_80;
}
BuildMI(MBB, MI, get(Opc), DestReg);
return;

View File

@ -19,3 +19,42 @@ define {x86_fp80, x86_fp80} @test2() {
ret x86_fp80 %A, x86_fp80 %A
}
; Uses both values.
define void @call1(x86_fp80 *%P1, x86_fp80 *%P2) {
%a = call {x86_fp80,x86_fp80} @test()
%b = getresult {x86_fp80,x86_fp80} %a, 0
store x86_fp80 %b, x86_fp80* %P1
%c = getresult {x86_fp80,x86_fp80} %a, 1
store x86_fp80 %c, x86_fp80* %P2
ret void
}
; Uses both values, requires fxch
define void @call2(x86_fp80 *%P1, x86_fp80 *%P2) {
%a = call {x86_fp80,x86_fp80} @test()
%b = getresult {x86_fp80,x86_fp80} %a, 1
store x86_fp80 %b, x86_fp80* %P1
%c = getresult {x86_fp80,x86_fp80} %a, 0
store x86_fp80 %c, x86_fp80* %P2
ret void
}
; Uses ST(0), ST(1) is dead but must be popped.
define void @call3(x86_fp80 *%P1, x86_fp80 *%P2) {
%a = call {x86_fp80,x86_fp80} @test()
%b = getresult {x86_fp80,x86_fp80} %a, 0
store x86_fp80 %b, x86_fp80* %P1
ret void
}
; Uses ST(1), ST(0) is dead and must be popped.
define void @call4(x86_fp80 *%P1, x86_fp80 *%P2) {
%a = call {x86_fp80,x86_fp80} @test()
%c = getresult {x86_fp80,x86_fp80} %a, 1
store x86_fp80 %c, x86_fp80* %P2
ret void
}