Skip to content
X86ISelLowering.cpp 160 KiB
Newer Older
    }
    addFullAddress(BuildMI(BB, Opc, 5), AM).addReg(MI->getOperand(4).getReg());

    // Reload the original control word now.
    addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);

    delete MI;   // The pseudo instruction is gone now.
    return BB;
  }
  }
}

//===----------------------------------------------------------------------===//
//                           X86 Optimization Hooks
//===----------------------------------------------------------------------===//

void X86TargetLowering::computeMaskedBitsForTargetNode(const SDOperand Op,
                                                       uint64_t Mask,
                                                       uint64_t &KnownZero, 
                                                       uint64_t &KnownOne,
                                                       unsigned Depth) const {
  unsigned Opc = Op.getOpcode();
Evan Cheng's avatar
Evan Cheng committed
  assert((Opc >= ISD::BUILTIN_OP_END ||
          Opc == ISD::INTRINSIC_WO_CHAIN ||
          Opc == ISD::INTRINSIC_W_CHAIN ||
          Opc == ISD::INTRINSIC_VOID) &&
         "Should use MaskedValueIsZero if you don't know whether Op"
         " is a target node!");
Evan Cheng's avatar
Evan Cheng committed
  KnownZero = KnownOne = 0;   // Don't know anything.
  switch (Opc) {
Evan Cheng's avatar
Evan Cheng committed
  default: break;
  case X86ISD::SETCC: 
    KnownZero |= (MVT::getIntVTBitMask(Op.getValueType()) ^ 1ULL);
    break;
/// getShuffleScalarElt - Returns the scalar element that will make up the ith
/// element of the result of the vector shuffle.
static SDOperand getShuffleScalarElt(SDNode *N, unsigned i, SelectionDAG &DAG) {
  MVT::ValueType VT = N->getValueType(0);
  SDOperand PermMask = N->getOperand(2);
  unsigned NumElems = PermMask.getNumOperands();
  SDOperand V = (i < NumElems) ? N->getOperand(0) : N->getOperand(1);
  i %= NumElems;
  if (V.getOpcode() == ISD::SCALAR_TO_VECTOR) {
    return (i == 0)
      ? V.getOperand(0) : DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(VT));
  } else if (V.getOpcode() == ISD::VECTOR_SHUFFLE) {
    SDOperand Idx = PermMask.getOperand(i);
    if (Idx.getOpcode() == ISD::UNDEF)
      return DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(VT));
    return getShuffleScalarElt(V.Val,cast<ConstantSDNode>(Idx)->getValue(),DAG);
  }
  return SDOperand();
}

/// isGAPlusOffset - Returns true (and the GlobalValue and the offset) if the
/// node is a GlobalAddress + an offset.
static bool isGAPlusOffset(SDNode *N, GlobalValue* &GA, int64_t &Offset) {
  if (N->getOpcode() == X86ISD::Wrapper) {
    if (dyn_cast<GlobalAddressSDNode>(N->getOperand(0))) {
      GA = cast<GlobalAddressSDNode>(N->getOperand(0))->getGlobal();
      return true;
    }
  } else if (N->getOpcode() == ISD::ADD) {
    SDOperand N1 = N->getOperand(0);
    SDOperand N2 = N->getOperand(1);
    if (isGAPlusOffset(N1.Val, GA, Offset)) {
      ConstantSDNode *V = dyn_cast<ConstantSDNode>(N2);
      if (V) {
        Offset += V->getSignExtended();
        return true;
      }
    } else if (isGAPlusOffset(N2.Val, GA, Offset)) {
      ConstantSDNode *V = dyn_cast<ConstantSDNode>(N1);
      if (V) {
        Offset += V->getSignExtended();
        return true;
      }
    }
  }
  return false;
}

/// isConsecutiveLoad - Returns true if N is loading from an address of Base
/// + Dist * Size.
static bool isConsecutiveLoad(SDNode *N, SDNode *Base, int Dist, int Size,
                              MachineFrameInfo *MFI) {
  if (N->getOperand(0).Val != Base->getOperand(0).Val)
    return false;

  SDOperand Loc = N->getOperand(1);
  SDOperand BaseLoc = Base->getOperand(1);
  if (Loc.getOpcode() == ISD::FrameIndex) {
    if (BaseLoc.getOpcode() != ISD::FrameIndex)
      return false;
    int FI  = dyn_cast<FrameIndexSDNode>(Loc)->getIndex();
    int BFI = dyn_cast<FrameIndexSDNode>(BaseLoc)->getIndex();
    int FS  = MFI->getObjectSize(FI);
    int BFS = MFI->getObjectSize(BFI);
    if (FS != BFS || FS != Size) return false;
    return MFI->getObjectOffset(FI) == (MFI->getObjectOffset(BFI) + Dist*Size);
  } else {
    GlobalValue *GV1 = NULL;
    GlobalValue *GV2 = NULL;
    int64_t Offset1 = 0;
    int64_t Offset2 = 0;
    bool isGA1 = isGAPlusOffset(Loc.Val, GV1, Offset1);
    bool isGA2 = isGAPlusOffset(BaseLoc.Val, GV2, Offset2);
    if (isGA1 && isGA2 && GV1 == GV2)
      return Offset1 == (Offset2 + Dist*Size);
  }

  return false;
}

static bool isBaseAlignment16(SDNode *Base, MachineFrameInfo *MFI,
                              const X86Subtarget *Subtarget) {
  GlobalValue *GV;
  int64_t Offset;
  if (isGAPlusOffset(Base, GV, Offset))
    return (GV->getAlignment() >= 16 && (Offset % 16) == 0);
  else {
    assert(Base->getOpcode() == ISD::FrameIndex && "Unexpected base node!");
    int BFI = dyn_cast<FrameIndexSDNode>(Base)->getIndex();
    if (BFI < 0)
      // Fixed objects do not specify alignment, however the offsets are known.
      return ((Subtarget->getStackAlignment() % 16) == 0 &&
              (MFI->getObjectOffset(BFI) % 16) == 0);
    else
      return MFI->getObjectAlignment(BFI) >= 16;
  }
  return false;
}


/// PerformShuffleCombine - Combine a vector_shuffle that is equal to
/// build_vector load1, load2, load3, load4, <0, 1, 2, 3> into a 128-bit load
/// if the load addresses are consecutive, non-overlapping, and in the right
/// order.
static SDOperand PerformShuffleCombine(SDNode *N, SelectionDAG &DAG,
                                       const X86Subtarget *Subtarget) {
  MachineFunction &MF = DAG.getMachineFunction();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  MVT::ValueType VT = N->getValueType(0);
  MVT::ValueType EVT = MVT::getVectorBaseType(VT);
  SDOperand PermMask = N->getOperand(2);
  int NumElems = (int)PermMask.getNumOperands();
  SDNode *Base = NULL;
  for (int i = 0; i < NumElems; ++i) {
    SDOperand Idx = PermMask.getOperand(i);
    if (Idx.getOpcode() == ISD::UNDEF) {
      if (!Base) return SDOperand();
    } else {
      SDOperand Arg =
        getShuffleScalarElt(N, cast<ConstantSDNode>(Idx)->getValue(), DAG);
      if (!Arg.Val || Arg.getOpcode() != ISD::LOAD)
        return SDOperand();
      if (!Base)
        Base = Arg.Val;
      else if (!isConsecutiveLoad(Arg.Val, Base,
                                  i, MVT::getSizeInBits(EVT)/8,MFI))
        return SDOperand();
    }
  }

  bool isAlign16 = isBaseAlignment16(Base->getOperand(1).Val, MFI, Subtarget);
  if (isAlign16)
    return DAG.getLoad(VT, Base->getOperand(0), Base->getOperand(1),
                       Base->getOperand(2));
    // Just use movups, it's shorter.
Evan Cheng's avatar
Evan Cheng committed
    std::vector<MVT::ValueType> Tys;
    Tys.push_back(MVT::v4f32);
    Tys.push_back(MVT::Other);
    SmallVector<SDOperand, 3> Ops;
    Ops.push_back(Base->getOperand(0));
    Ops.push_back(Base->getOperand(1));
    Ops.push_back(Base->getOperand(2));
    return DAG.getNode(ISD::BIT_CONVERT, VT,
Evan Cheng's avatar
Evan Cheng committed
                       DAG.getNode(X86ISD::LOAD_UA, Tys, &Ops[0], Ops.size()));
}

SDOperand X86TargetLowering::PerformDAGCombine(SDNode *N, 
                                               DAGCombinerInfo &DCI) const {
  TargetMachine &TM = getTargetMachine();
  SelectionDAG &DAG = DCI.DAG;
  switch (N->getOpcode()) {
  default: break;
  case ISD::VECTOR_SHUFFLE:
    return PerformShuffleCombine(N, DAG, Subtarget);
//===----------------------------------------------------------------------===//
//                           X86 Inline Assembly Support
//===----------------------------------------------------------------------===//

/// getConstraintType - Given a constraint letter, return the type of
/// constraint it is for this target.
X86TargetLowering::ConstraintType
X86TargetLowering::getConstraintType(char ConstraintLetter) const {
  switch (ConstraintLetter) {
  case 'A':
  case 'r':
  case 'R':
  case 'l':
  case 'q':
  case 'Q':
  case 'x':
  case 'Y':
    return C_RegisterClass;
  default: return TargetLowering::getConstraintType(ConstraintLetter);
  }
}

std::vector<unsigned> X86TargetLowering::
getRegClassForInlineAsmConstraint(const std::string &Constraint,
                                  MVT::ValueType VT) const {
  if (Constraint.size() == 1) {
    // FIXME: not handling fp-stack yet!
    // FIXME: not handling MMX registers yet ('y' constraint).
    switch (Constraint[0]) {      // GCC X86 Constraint Letters
    default: break;  // Unknown constraint letter
    case 'A':   // EAX/EDX
      if (VT == MVT::i32 || VT == MVT::i64)
        return make_vector<unsigned>(X86::EAX, X86::EDX, 0);
      break;
    case 'r':   // GENERAL_REGS
    case 'R':   // LEGACY_REGS
      if (VT == MVT::i32)
        return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX,
                                     X86::ESI, X86::EDI, X86::EBP, X86::ESP, 0);
      else if (VT == MVT::i16)
        return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX, 
                                     X86::SI, X86::DI, X86::BP, X86::SP, 0);
      else if (VT == MVT::i8)
        return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
      break;
    case 'l':   // INDEX_REGS
      if (VT == MVT::i32)
        return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX,
                                     X86::ESI, X86::EDI, X86::EBP, 0);
      else if (VT == MVT::i16)
        return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX, 
                                     X86::SI, X86::DI, X86::BP, 0);
      else if (VT == MVT::i8)
        return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
      break;
    case 'q':   // Q_REGS (GENERAL_REGS in 64-bit mode)
    case 'Q':   // Q_REGS
      if (VT == MVT::i32)
        return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX, 0);
      else if (VT == MVT::i16)
        return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX, 0);
      else if (VT == MVT::i8)
        return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
        break;
    case 'x':   // SSE_REGS if SSE1 allowed
      if (Subtarget->hasSSE1())
        return make_vector<unsigned>(X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
                                     X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7,
                                     0);
      return std::vector<unsigned>();
    case 'Y':   // SSE_REGS if SSE2 allowed
      if (Subtarget->hasSSE2())
        return make_vector<unsigned>(X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
                                     X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7,
                                     0);
      return std::vector<unsigned>();
    }
  }
  
  return std::vector<unsigned>();

std::pair<unsigned, const TargetRegisterClass*> 
X86TargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
                                                MVT::ValueType VT) const {
  // Use the default implementation in TargetLowering to convert the register
  // constraint into a member of a register class.
  std::pair<unsigned, const TargetRegisterClass*> Res;
  Res = TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
  
  // Not found?  Bail out.
  if (Res.second == 0) return Res;
  
  // Otherwise, check to see if this is a register class of the wrong value
  // type.  For example, we want to map "{ax},i32" -> {eax}, we don't want it to
  // turn into {ax},{dx}.
  if (Res.second->hasType(VT))
    return Res;   // Correct type already, nothing to do.
  
  // All of the single-register GCC register classes map their values onto
  // 16-bit register pieces "ax","dx","cx","bx","si","di","bp","sp".  If we
  // really want an 8-bit or 32-bit register, map to the appropriate register
  // class and return the appropriate register.
  if (Res.second != X86::GR16RegisterClass)
    return Res;
  
  if (VT == MVT::i8) {
    unsigned DestReg = 0;
    switch (Res.first) {
    default: break;
    case X86::AX: DestReg = X86::AL; break;
    case X86::DX: DestReg = X86::DL; break;
    case X86::CX: DestReg = X86::CL; break;
    case X86::BX: DestReg = X86::BL; break;
    }
    if (DestReg) {
      Res.first = DestReg;
      Res.second = Res.second = X86::GR8RegisterClass;
    }
  } else if (VT == MVT::i32) {
    unsigned DestReg = 0;
    switch (Res.first) {
    default: break;
    case X86::AX: DestReg = X86::EAX; break;
    case X86::DX: DestReg = X86::EDX; break;
    case X86::CX: DestReg = X86::ECX; break;
    case X86::BX: DestReg = X86::EBX; break;
    case X86::SI: DestReg = X86::ESI; break;
    case X86::DI: DestReg = X86::EDI; break;
    case X86::BP: DestReg = X86::EBP; break;
    case X86::SP: DestReg = X86::ESP; break;
    }
    if (DestReg) {
      Res.first = DestReg;
      Res.second = Res.second = X86::GR32RegisterClass;
    }
  }
  
  return Res;
}