mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-14 00:32:55 +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!");
|
||||
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)));
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user