mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-14 09:38:40 +00:00
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:
parent
ae60ddc22a
commit
24e0a546b4
@ -933,6 +933,42 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) {
|
|||||||
assert(StackTop == 0 && "Stack should be empty after a call!");
|
assert(StackTop == 0 && "Stack should be empty after a call!");
|
||||||
pushReg(getFPReg(MI->getOperand(0)));
|
pushReg(getFPReg(MI->getOperand(0)));
|
||||||
break;
|
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:
|
case X86::FpGET_ST0_ST1:
|
||||||
assert(StackTop == 0 && "Stack should be empty after a call!");
|
assert(StackTop == 0 && "Stack should be empty after a call!");
|
||||||
pushReg(getFPReg(MI->getOperand(0)));
|
pushReg(getFPReg(MI->getOperand(0)));
|
||||||
|
@ -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_64 : FpI_<(outs RFP64:$dst), (ins), SpecialFP, []>; // FPR = ST(0)
|
||||||
def FpGET_ST0_80 : FpI_<(outs RFP80:$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,
|
def FpGET_ST0_ST1 : FpI_<(outs RFP80:$dst1, RFP80:$dst2), (ins), SpecialFP,
|
||||||
[]>; // FPR = ST(0), FPR = ST(1)
|
[]>; // FPR = ST(0), FPR = ST(1)
|
||||||
|
|
||||||
|
@ -1487,16 +1487,18 @@ void X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
|
|||||||
|
|
||||||
// Moving from ST(0) turns into FpGET_ST0_32 etc.
|
// Moving from ST(0) turns into FpGET_ST0_32 etc.
|
||||||
if (SrcRC == &X86::RSTRegClass) {
|
if (SrcRC == &X86::RSTRegClass) {
|
||||||
// Copying from ST(0). FIXME: handle ST(1) also
|
// Copying from ST(0)/ST(1).
|
||||||
assert(SrcReg == X86::ST0 && "Can only copy from TOS right now");
|
assert((SrcReg == X86::ST0 || SrcReg == X86::ST1) &&
|
||||||
|
"Can only copy from ST(0)/ST(1) right now");
|
||||||
|
bool isST0 = SrcReg == X86::ST0;
|
||||||
unsigned Opc;
|
unsigned Opc;
|
||||||
if (DestRC == &X86::RFP32RegClass)
|
if (DestRC == &X86::RFP32RegClass)
|
||||||
Opc = X86::FpGET_ST0_32;
|
Opc = isST0 ? X86::FpGET_ST0_32 : X86::FpGET_ST1_32;
|
||||||
else if (DestRC == &X86::RFP64RegClass)
|
else if (DestRC == &X86::RFP64RegClass)
|
||||||
Opc = X86::FpGET_ST0_64;
|
Opc = isST0 ? X86::FpGET_ST0_64 : X86::FpGET_ST1_64;
|
||||||
else {
|
else {
|
||||||
assert(DestRC == &X86::RFP80RegClass);
|
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);
|
BuildMI(MBB, MI, get(Opc), DestReg);
|
||||||
return;
|
return;
|
||||||
|
@ -19,3 +19,42 @@ define {x86_fp80, x86_fp80} @test2() {
|
|||||||
ret x86_fp80 %A, x86_fp80 %A
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user