From 24e0a546b40d67dd3662273eb4aef30c230a15ef Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 21 Mar 2008 06:38:26 +0000 Subject: [PATCH] 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 --- lib/Target/X86/X86FloatingPoint.cpp | 36 +++++++++++++++++++++++++ lib/Target/X86/X86InstrFPStack.td | 9 +++++++ lib/Target/X86/X86InstrInfo.cpp | 12 +++++---- test/CodeGen/X86/fp-stack-2results.ll | 39 +++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 5 deletions(-) diff --git a/lib/Target/X86/X86FloatingPoint.cpp b/lib/Target/X86/X86FloatingPoint.cpp index 2070cc5d133..897edcbaddb 100644 --- a/lib/Target/X86/X86FloatingPoint.cpp +++ b/lib/Target/X86/X86FloatingPoint.cpp @@ -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))); diff --git a/lib/Target/X86/X86InstrFPStack.td b/lib/Target/X86/X86InstrFPStack.td index d37ecf80899..be9129471cc 100644 --- a/lib/Target/X86/X86InstrFPStack.td +++ b/lib/Target/X86/X86InstrFPStack.td @@ -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) diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index 650ab415ee5..dc267942e18 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -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; diff --git a/test/CodeGen/X86/fp-stack-2results.ll b/test/CodeGen/X86/fp-stack-2results.ll index dcb2031a504..f47fd7472ec 100644 --- a/test/CodeGen/X86/fp-stack-2results.ll +++ b/test/CodeGen/X86/fp-stack-2results.ll @@ -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 +} + -- 2.34.1