Skip to content
X86FloatingPoint.cpp 45.3 KiB
Newer Older
  case X86::FpSET_ST0_32:
  case X86::FpSET_ST0_64:
Rafael Espindola's avatar
Rafael Espindola committed
  case X86::FpSET_ST0_80: {
Rafael Espindola's avatar
Rafael Espindola committed
    unsigned Op0 = getFPReg(MI->getOperand(0));

Rafael Espindola's avatar
Rafael Espindola committed
    // FpSET_ST0_80 is generated by copyRegToReg for both function return
    // and inline assembly with the "st" constrain. In the latter case,
Rafael Espindola's avatar
Rafael Espindola committed
    // it is possible for ST(0) to be alive after this instruction.
Rafael Espindola's avatar
Rafael Espindola committed
    if (!MI->killsRegister(X86::FP0 + Op0)) {
      // Duplicate Op0
Rafael Espindola's avatar
Rafael Espindola committed
      duplicateToTop(0, 7 /*temp register*/, I);
Rafael Espindola's avatar
Rafael Espindola committed
    } else {
      moveToTop(Op0, I);
Rafael Espindola's avatar
Rafael Espindola committed
    }
Evan Cheng's avatar
Evan Cheng committed
    --StackTop;   // "Forget" we have something on the top of stack!
    break;
Rafael Espindola's avatar
Rafael Espindola committed
  }
Evan Cheng's avatar
Evan Cheng committed
  case X86::FpSET_ST1_32:
  case X86::FpSET_ST1_64:
  case X86::FpSET_ST1_80:
    // StackTop can be 1 if a FpSET_ST0_* was before this. Exchange them.
    if (StackTop == 1) {
      BuildMI(*MBB, I, dl, TII->get(X86::XCH_F)).addReg(X86::ST1);
Evan Cheng's avatar
Evan Cheng committed
      NumFXCH++;
      StackTop = 0;
      break;
    }
    assert(StackTop == 2 && "Stack should have two element on it to return!");
Chris Lattner's avatar
Chris Lattner committed
    --StackTop;   // "Forget" we have something on the top of stack!
    break;
  case X86::MOV_Fp3232:
  case X86::MOV_Fp3264:
  case X86::MOV_Fp6432:
  case X86::MOV_Fp6464: 
  case X86::MOV_Fp3280:
  case X86::MOV_Fp6480:
  case X86::MOV_Fp8032:
  case X86::MOV_Fp8064: 
  case X86::MOV_Fp8080: {
    const MachineOperand &MO1 = MI->getOperand(1);
    unsigned SrcReg = getFPReg(MO1);

    const MachineOperand &MO0 = MI->getOperand(0);
    // These can be created due to inline asm. Two address pass can introduce
    // copies from RFP registers to virtual registers.
    if (MO0.getReg() == X86::ST0 && SrcReg == 0) {
      assert(MO1.isKill());
      // Treat %ST0<def> = MOV_Fp8080 %FP0<kill>
      // like  FpSET_ST0_80 %FP0<kill>, %ST0<imp-def>
      assert((StackTop == 1 || StackTop == 2)
             && "Stack should have one or two element on it to return!");
      --StackTop;   // "Forget" we have something on the top of stack!
      break;
    } else if (MO0.getReg() == X86::ST1 && SrcReg == 1) {
      assert(MO1.isKill());
      // Treat %ST1<def> = MOV_Fp8080 %FP1<kill>
      // like  FpSET_ST1_80 %FP0<kill>, %ST1<imp-def>
      // StackTop can be 1 if a FpSET_ST0_* was before this. Exchange them.
      if (StackTop == 1) {
        BuildMI(*MBB, I, dl, TII->get(X86::XCH_F)).addReg(X86::ST1);
        NumFXCH++;
        StackTop = 0;
        break;
      }
      assert(StackTop == 2 && "Stack should have two element on it to return!");
      --StackTop;   // "Forget" we have something on the top of stack!
      break;
    }
Chris Lattner's avatar
Chris Lattner committed

    if (MI->killsRegister(X86::FP0+SrcReg)) {
Chris Lattner's avatar
Chris Lattner committed
      // If the input operand is killed, we can just change the owner of the
      // incoming stack slot into the result.
      unsigned Slot = getSlot(SrcReg);
      assert(Slot < 7 && DestReg < 7 && "FpMOV operands invalid!");
      Stack[Slot] = DestReg;
      RegMap[DestReg] = Slot;

    } else {
      // For FMOV we just duplicate the specified value to a new stack slot.
      // This could be made better, but would require substantial changes.
      duplicateToTop(SrcReg, DestReg, I);
    }
Chris Lattner's avatar
Chris Lattner committed
    break;
  case TargetInstrInfo::INLINEASM: {
    // The inline asm MachineInstr currently only *uses* FP registers for the
    // 'f' constraint.  These should be turned into the current ST(x) register
    // in the machine instr.  Also, any kills should be explicitly popped after
    // the inline asm.
    unsigned Kills[7];
    unsigned NumKills = 0;
    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() && "Only handle inline asm uses right now");
      
      unsigned FPReg = getFPReg(Op);
      Op.setReg(getSTReg(FPReg));
      
      // If we kill this operand, make sure to pop it from the stack after the
      // asm.  We just remember it for now, and pop them all off at the end in
      // a batch.
      if (Op.isKill())
        Kills[NumKills++] = FPReg;
    }

    // If this asm kills any FP registers (is the last use of them) we must
    // explicitly emit pop instructions for them.  Do this now after the asm has
    // executed so that the ST(x) numbers are not off (which would happen if we
    // did this inline with operand rewriting).
    //
    // Note: this might be a non-optimal pop sequence.  We might be able to do
    // better by trying to pop in stack order or something.
    MachineBasicBlock::iterator InsertPt = MI;
    while (NumKills)
      freeStackSlotAfter(InsertPt, Kills[--NumKills]);

    // Don't delete the inline asm!
    return;
  }
      
  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)
      // FP Register uses must be kills unless there are two uses of the same
      // register, in which case only one will be a kill.
      assert(Op.isUse() &&
             (Op.isKill() ||                        // Marked kill.
              getFPReg(Op) == FirstFPRegOp ||       // Second instance.
              MI->killsRegister(Op.getReg())) &&    // Later use is marked kill.
             "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;
    }
    
    // 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(1) == SecondFPRegOp && "Unknown regs live");
Chris Lattner's avatar
Chris Lattner committed
  }

  I = MBB->erase(I);  // Remove the pseudo instruction
  --I;
Chris Lattner's avatar
Chris Lattner committed
}