Add support for calls that return two FP values in
authorChris Lattner <sabre@nondot.org>
Fri, 21 Mar 2008 06:38:26 +0000 (06:38 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 21 Mar 2008 06:38:26 +0000 (06:38 +0000)
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
lib/Target/X86/X86InstrFPStack.td
lib/Target/X86/X86InstrInfo.cpp
test/CodeGen/X86/fp-stack-2results.ll

index 2070cc5d133f6f299c9058961e2550f1b6f78533..897edcbaddb52ac4828657fc5a806a68856b3a37 100644 (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)));
index d37ecf80899df834130b1452d7e92e575744cc9c..be9129471ccfd993ef70d132ab8054e08dd23b5f 100644 (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)
 
index 650ab415ee5afcd583121191cef5c422f0245e13..dc267942e1841b08950ce781cf0a8bc316de9160 100644 (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;
index dcb2031a504d6b89d6df47c732367633fd018d49..f47fd7472ecb4c7509876f144939a2f60817ba78 100644 (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 
+}
+