[llvm-commits] [llvm] r48634 - in /llvm/trunk: lib/Target/X86/X86FloatingPoint.cpp lib/Target/X86/X86InstrFPStack.td lib/Target/X86/X86InstrInfo.cpp test/CodeGen/X86/fp-stack-2results.ll

Chris Lattner sabre at nondot.org
Thu Mar 20 23:38:27 PDT 2008


Author: lattner
Date: Fri Mar 21 01:38:26 2008
New Revision: 48634

URL: http://llvm.org/viewvc/llvm-project?rev=48634&view=rev
Log:
Add support for calls that return two FP values in
ST(0)/ST(1).

Modified:
    llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp
    llvm/trunk/lib/Target/X86/X86InstrFPStack.td
    llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
    llvm/trunk/test/CodeGen/X86/fp-stack-2results.ll

Modified: llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp?rev=48634&r1=48633&r2=48634&view=diff

==============================================================================
--- llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp Fri Mar 21 01:38:26 2008
@@ -933,6 +933,42 @@
     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)));

Modified: llvm/trunk/lib/Target/X86/X86InstrFPStack.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrFPStack.td?rev=48634&r1=48633&r2=48634&view=diff

==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrFPStack.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrFPStack.td Fri Mar 21 01:38:26 2008
@@ -136,6 +136,15 @@
 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)
 

Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.cpp?rev=48634&r1=48633&r2=48634&view=diff

==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.cpp Fri Mar 21 01:38:26 2008
@@ -1487,16 +1487,18 @@
   
   // 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;

Modified: llvm/trunk/test/CodeGen/X86/fp-stack-2results.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/fp-stack-2results.ll?rev=48634&r1=48633&r2=48634&view=diff

==============================================================================
--- llvm/trunk/test/CodeGen/X86/fp-stack-2results.ll (original)
+++ llvm/trunk/test/CodeGen/X86/fp-stack-2results.ll Fri Mar 21 01:38:26 2008
@@ -19,3 +19,42 @@
   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 
+}
+





More information about the llvm-commits mailing list