[llvm-commits] [llvm] r48209 - in /llvm/trunk/lib/Target/X86: X86FloatingPoint.cpp X86ISelDAGToDAG.cpp X86ISelLowering.cpp X86InstrInfo.td

Chris Lattner sabre at nondot.org
Mon Mar 10 20:23:40 PDT 2008


Author: lattner
Date: Mon Mar 10 22:23:40 2008
New Revision: 48209

URL: http://llvm.org/viewvc/llvm-project?rev=48209&view=rev
Log:
Change the model for FP Stack return to use fp operands on the 
RET instruction instead of using FpSET_ST0_32.  This also generalizes
the code to handling returning of multiple FP results.

Modified:
    llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp
    llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp
    llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
    llvm/trunk/lib/Target/X86/X86InstrInfo.td

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

==============================================================================
--- llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86FloatingPoint.cpp Mon Mar 10 22:23:40 2008
@@ -75,26 +75,31 @@
       cerr << "\n";
     }
   private:
+    /// isStackEmpty - Return true if the FP stack is empty.
+    bool isStackEmpty() const {
+      return StackTop == 0;
+    }
+    
     // getSlot - Return the stack slot number a particular register number is
-    // in...
+    // in.
     unsigned getSlot(unsigned RegNo) const {
       assert(RegNo < 8 && "Regno out of range!");
       return RegMap[RegNo];
     }
 
-    // getStackEntry - Return the X86::FP<n> register in register ST(i)
+    // getStackEntry - Return the X86::FP<n> register in register ST(i).
     unsigned getStackEntry(unsigned STi) const {
       assert(STi < StackTop && "Access past stack top!");
       return Stack[StackTop-1-STi];
     }
 
     // getSTReg - Return the X86::ST(i) register which contains the specified
-    // FP<RegNo> register
+    // FP<RegNo> register.
     unsigned getSTReg(unsigned RegNo) const {
       return StackTop - 1 - getSlot(RegNo) + llvm::X86::ST0;
     }
 
-    // pushReg - Push the specified FP<n> register onto the stack
+    // pushReg - Push the specified FP<n> register onto the stack.
     void pushReg(unsigned Reg) {
       assert(Reg < 8 && "Register number out of range!");
       assert(StackTop < 8 && "Stack overflow!");
@@ -103,22 +108,22 @@
     }
 
     bool isAtTop(unsigned RegNo) const { return getSlot(RegNo) == StackTop-1; }
-    void moveToTop(unsigned RegNo, MachineBasicBlock::iterator &I) {
-      if (!isAtTop(RegNo)) {
-        unsigned STReg = getSTReg(RegNo);
-        unsigned RegOnTop = getStackEntry(0);
-
-        // 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]);
-
-        // Emit an fxch to update the runtime processors version of the state
-        BuildMI(*MBB, I, TII->get(X86::XCH_F)).addReg(STReg);
-        NumFXCH++;
-      }
+    void moveToTop(unsigned RegNo, MachineBasicBlock::iterator I) {
+      if (isAtTop(RegNo)) return;
+      
+      unsigned STReg = getSTReg(RegNo);
+      unsigned RegOnTop = getStackEntry(0);
+
+      // 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]);
+
+      // Emit an fxch to update the runtime processors version of the state.
+      BuildMI(*MBB, I, TII->get(X86::XCH_F)).addReg(STReg);
+      NumFXCH++;
     }
 
     void duplicateToTop(unsigned RegNo, unsigned AsReg, MachineInstr *I) {
@@ -268,7 +273,7 @@
     Changed = true;
   }
 
-  assert(StackTop == 0 && "Stack not empty at end of basic block?");
+  assert(isStackEmpty() && "Stack not empty at end of basic block?");
   return Changed;
 }
 
@@ -960,6 +965,83 @@
       duplicateToTop(SrcReg, DestReg, I);
     }
     break;
+  case X86::RET:
+  case X86::RETI:
+    // If RET has an FP register use operand, pass the first one in ST(0) and
+    // the second one in ST(1).
+    if (isStackEmpty()) return;  // Quick check to see if any are possible.
+    
+    // Find the register operands.
+    unsigned FirstFPRegOp = ~0U, SecondFPRegOp = ~0U;
+    
+    for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+      MachineOperand &Op = MI->getOperand(i);
+      if (!Op.isReg() || Op.getReg() < X86::FP0 || Op.getReg() > X86::FP6)
+        continue;
+      assert(Op.isUse() && Op.isKill() &&
+             "Ret only defs operands, and values aren't live beyond it");
+
+      if (FirstFPRegOp == ~0U)
+        FirstFPRegOp = getFPReg(Op);
+      else {
+        assert(SecondFPRegOp == ~0U && "More than two fp operands!");
+        SecondFPRegOp = getFPReg(Op);
+      }
+
+      // Remove the operand so that later passes don't see it.
+      MI->RemoveOperand(i);
+      --i, --e;
+    }
+    
+    // There are only four possibilities here:
+    // 1) we are returning a single FP value.  In this case, it has to be in
+    //    ST(0) already, so just declare success by removing the value from the
+    //    FP Stack.
+    if (SecondFPRegOp == ~0U) {
+      // Assert that the top of stack contains the right FP register.
+      assert(StackTop == 1 && FirstFPRegOp == getStackEntry(0) &&
+             "Top of stack not the right register for RET!");
+      
+      // Ok, everything is good, mark the value as not being on the stack
+      // anymore so that our assertion about the stack being empty at end of
+      // block doesn't fire.
+      StackTop = 0;
+      return;
+    }
+    
+    assert(0 && "TODO: This code should work, but has never been tested."
+           "Test it when we have multiple FP return values working");
+    
+    // Otherwise, we are returning two values:
+    // 2) If returning the same value for both, we only have one thing in the FP
+    //    stack.  Consider:  RET FP1, FP1
+    if (StackTop == 1) {
+      assert(FirstFPRegOp == SecondFPRegOp && FirstFPRegOp == getStackEntry(0)&&
+             "Stack misconfiguration for RET!");
+      
+      // Duplicate the TOS so that we return it twice.  Just pick some other FPx
+      // register to hold it.
+      unsigned NewReg = (FirstFPRegOp+1)%7;
+      duplicateToTop(FirstFPRegOp, NewReg, MI);
+      FirstFPRegOp = NewReg;
+    }
+    
+    /// Okay we know we have two different FPx operands now:
+    assert(StackTop == 2 && "Must have two values live!");
+    
+    /// 3) If SecondFPRegOp is currently in ST(0) and FirstFPRegOp is currently
+    ///    in ST(1).  In this case, emit an fxch.
+    if (getStackEntry(0) == SecondFPRegOp) {
+      assert(getStackEntry(1) == FirstFPRegOp && "Unknown regs live");
+      moveToTop(FirstFPRegOp, MI);
+    }
+    
+    /// 4) Finally, FirstFPRegOp must be in ST(0) and SecondFPRegOp must be in
+    /// ST(1).  Just remove both from our understanding of the stack and return.
+    assert(getStackEntry(0) == FirstFPRegOp && "Unknown regs live");
+    assert(getStackEntry(0) == SecondFPRegOp && "Unknown regs live");
+    StackTop = 0;
+    return;
   }
   }
 

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

==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp Mon Mar 10 22:23:40 2008
@@ -1168,6 +1168,35 @@
     case X86ISD::GlobalBaseReg: 
       return getGlobalBaseReg();
 
+    // FIXME: This is a workaround for a tblgen problem: rdar://5791600
+    case X86ISD::RET_FLAG:
+      if (ConstantSDNode *Amt = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+        if (Amt->getSignExtended() != 0) break;
+        
+        // Match (X86retflag 0).
+        SDOperand Chain = N.getOperand(0);
+        bool HasInFlag = N.getOperand(N.getNumOperands()-1).getValueType()
+                          == MVT::Flag;
+        SmallVector<SDOperand, 8> Ops0;
+        AddToISelQueue(Chain);
+        SDOperand InFlag(0, 0);
+        if (HasInFlag) {
+          InFlag = N.getOperand(N.getNumOperands()-1);
+          AddToISelQueue(InFlag);
+        }
+        for (unsigned i = 2, e = N.getNumOperands()-(HasInFlag?1:0); i != e;
+             ++i) {
+          AddToISelQueue(N.getOperand(i));
+          Ops0.push_back(N.getOperand(i));
+        }
+        Ops0.push_back(Chain);
+        if (HasInFlag)
+          Ops0.push_back(InFlag);
+        return CurDAG->getTargetNode(X86::RET, MVT::Other,
+                                     &Ops0[0], Ops0.size());
+      }
+      break;
+      
     case X86ISD::FP_GET_ST0_ST1: {
       SDOperand Chain = N.getOperand(0);
       SDOperand InFlag = N.getOperand(1);

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

==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 10 22:23:40 2008
@@ -853,27 +853,41 @@
   // Regular return.
   SDOperand Flag;
 
+  SmallVector<SDOperand, 6> RetOps;
+  RetOps.push_back(Chain); // Operand #0 = Chain (updated below)
+  // Operand #1 = Bytes To Pop
+  RetOps.push_back(DAG.getConstant(getBytesToPopOnReturn(), MVT::i16));
+  
   // Copy the result values into the output registers.
   for (unsigned i = 0; i != RVLocs.size(); ++i) {
     CCValAssign &VA = RVLocs[i];
     assert(VA.isRegLoc() && "Can only return in registers!");
     SDOperand ValToCopy = Op.getOperand(i*2+1);
     
-    // If this is a copy from an xmm register to ST(0), use an FPExtend to
-    // change the value to the FP stack register class.
-    if (RVLocs[i].getLocReg() == X86::ST0 &&
-        isScalarFPTypeInSSEReg(RVLocs[i].getValVT()))
-      ValToCopy = DAG.getNode(ISD::FP_EXTEND, MVT::f80, ValToCopy);
+    // Returns in ST0/ST1 are handled specially: these are pushed as operands to
+    // the RET instruction and handled by the FP Stackifier.
+    if (RVLocs[i].getLocReg() == X86::ST0 ||
+        RVLocs[i].getLocReg() == X86::ST1) {
+      // If this is a copy from an xmm register to ST(0), use an FPExtend to
+      // change the value to the FP stack register class.
+      if (isScalarFPTypeInSSEReg(RVLocs[i].getValVT()))
+        ValToCopy = DAG.getNode(ISD::FP_EXTEND, MVT::f80, ValToCopy);
+      RetOps.push_back(ValToCopy);
+      // Don't emit a copytoreg.
+      continue;
+    }
     
     Chain = DAG.getCopyToReg(Chain, VA.getLocReg(), ValToCopy, Flag);
     Flag = Chain.getValue(1);
   }
   
-  SDOperand BytesToPop = DAG.getConstant(getBytesToPopOnReturn(), MVT::i16);
+  RetOps[0] = Chain;  // Update chain.
+
+  // Add the flag if we have it.
   if (Flag.Val)
-    return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Chain, BytesToPop, Flag);
-  else
-    return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Chain, BytesToPop);
+    RetOps.push_back(Flag);
+  
+  return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, &RetOps[0], RetOps.size());
 }
 
 

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

==============================================================================
--- llvm/trunk/lib/Target/X86/X86InstrInfo.td (original)
+++ llvm/trunk/lib/Target/X86/X86InstrInfo.td Mon Mar 10 22:23:40 2008
@@ -39,7 +39,7 @@
                                      SDTCisVT<2, i8>]>;
 def SDTX86cas8 : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
 
-def SDTX86Ret     : SDTypeProfile<0, 1, [SDTCisVT<0, i16>]>;
+def SDTX86Ret     : SDTypeProfile<0, -1, [SDTCisVT<0, i16>]>;
 
 def SDT_X86CallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
 def SDT_X86CallSeqEnd   : SDCallSeqEnd<[ SDTCisVT<0, i32>,
@@ -269,8 +269,8 @@
 // ADJCALLSTACKDOWN/UP implicitly use/def ESP because they may be expanded into
 // a stack adjustment and the codegen must know that they may modify the stack
 // pointer before prolog-epilog rewriting occurs.
-// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become sub / add
-// which can clobber EFLAGS.
+// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
+// sub / add which can clobber EFLAGS.
 let Defs = [ESP, EFLAGS], Uses = [ESP] in {
 def ADJCALLSTACKDOWN : I<0, Pseudo, (outs), (ins i32imm:$amt),
                          "#ADJCALLSTACKDOWN",
@@ -306,9 +306,12 @@
 
 // Return instructions.
 let isTerminator = 1, isReturn = 1, isBarrier = 1,
-    hasCtrlDep = 1 in {
-  def RET    : I<0xC3, RawFrm, (outs), (ins), "ret", [(X86retflag 0)]>;
-  def RETI   : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt), "ret\t$amt",
+    hasCtrlDep = 1, FPForm = SpecialFP, FPFormBits = SpecialFP.Value in {
+  def RET    : I   <0xC3, RawFrm, (outs), (ins variable_ops),
+                    "ret",
+                    [/*(X86retflag 0)*/ /*FIXME: Disabled: rdar://5791600*/]>;
+  def RETI   : Ii16<0xC2, RawFrm, (outs), (ins i16imm:$amt, variable_ops),
+                    "ret\t$amt",
                     [(X86retflag imm:$amt)]>;
 }
 
@@ -384,7 +387,7 @@
 
 // Tail call stuff.
 
-def TAILCALL : I<0, Pseudo, (outs), (ins ),
+def TAILCALL : I<0, Pseudo, (outs), (ins),
                          "#TAILCALL",
                          []>;
 





More information about the llvm-commits mailing list