Skip to content
X86ISelLowering.cpp 127 KiB
Newer Older
    if (Values.size() > 2) {
      // Expand into a number of unpckl*.
      // e.g. for v4f32
      //   Step 1: unpcklps 0, 2 ==> X: <?, ?, 2, 0>
      //         : unpcklps 1, 3 ==> Y: <?, ?, 3, 1>
      //   Step 2: unpcklps X, Y ==>    <3, 2, 1, 0>
      MVT::ValueType VT = Op.getValueType();
      SDOperand PermMask = getUnpacklMask(NumElems, DAG);
      std::vector<SDOperand> V(NumElems);
      for (unsigned i = 0; i < NumElems; ++i)
        V[i] = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, Op.getOperand(i));
      NumElems >>= 1;
      while (NumElems != 0) {
        for (unsigned i = 0; i < NumElems; ++i)
          V[i] = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[i], V[i + NumElems],
                             PermMask);
    return SDOperand();
  }
    if (!isa<ConstantSDNode>(Op.getOperand(1)))
        return SDOperand();

    MVT::ValueType VT = Op.getValueType();
    if (MVT::getSizeInBits(VT) == 16) {
      // Transform it so it match pextrw which produces a 32-bit result.
      MVT::ValueType EVT = (MVT::ValueType)(VT+1);
      SDOperand Extract = DAG.getNode(X86ISD::PEXTRW, EVT,
                                      Op.getOperand(0), Op.getOperand(1));
      SDOperand Assert  = DAG.getNode(ISD::AssertZext, EVT, Extract,
                                      DAG.getValueType(VT));
      return DAG.getNode(ISD::TRUNCATE, VT, Assert);
    } else if (MVT::getSizeInBits(VT) == 32) {
      SDOperand Vec = Op.getOperand(0);
      unsigned Idx = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
      if (Idx == 0)
        return Op;

      // TODO: if Idex == 2, we can use unpckhps
      // SHUFPS the element to the lowest double word, then movss.
      MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
      SDOperand IdxNode = DAG.getConstant((Idx < 2) ? Idx : Idx+4,
                                          MVT::getVectorBaseType(MaskVT));
      std::vector<SDOperand> IdxVec;
      IdxVec.push_back(DAG.getConstant(Idx, MVT::getVectorBaseType(MaskVT)));
      IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
      IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
      IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
      SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT, IdxVec);
      Vec = DAG.getNode(ISD::VECTOR_SHUFFLE, Vec.getValueType(),
                        Vec, Vec, Mask);
      return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, VT, Vec,
                         DAG.getConstant(0, MVT::i32));
    } else if (MVT::getSizeInBits(VT) == 64) {
      SDOperand Vec = Op.getOperand(0);
      unsigned Idx = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
      if (Idx == 0)
        return Op;

      // UNPCKHPD the element to the lowest double word, then movsd.
      // Note if the lower 64 bits of the result of the UNPCKHPD is then stored
      // to a f64mem, the whole operation is folded into a single MOVHPDmr.
      MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
      std::vector<SDOperand> IdxVec;
      IdxVec.push_back(DAG.getConstant(1, MVT::getVectorBaseType(MaskVT)));
      IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
      SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT, IdxVec);
      Vec = DAG.getNode(ISD::VECTOR_SHUFFLE, Vec.getValueType(),
                        Vec, DAG.getNode(ISD::UNDEF, Vec.getValueType()), Mask);
      return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, VT, Vec,
                         DAG.getConstant(0, MVT::i32));
    }

    return SDOperand();
  }
  case ISD::INSERT_VECTOR_ELT: {
    // Transform it so it match pinsrw which expects a 16-bit value in a R32
    // as its second argument.
    MVT::ValueType VT = Op.getValueType();
    MVT::ValueType BaseVT = MVT::getVectorBaseType(VT);
    SDOperand N0 = Op.getOperand(0);
    SDOperand N1 = Op.getOperand(1);
    SDOperand N2 = Op.getOperand(2);
    if (MVT::getSizeInBits(BaseVT) == 16) {
      if (N1.getValueType() != MVT::i32)
        N1 = DAG.getNode(ISD::ANY_EXTEND, MVT::i32, N1);
      if (N2.getValueType() != MVT::i32)
        N2 = DAG.getConstant(cast<ConstantSDNode>(N2)->getValue(), MVT::i32);
      return DAG.getNode(X86ISD::PINSRW, VT, N0, N1, N2);
    } else if (MVT::getSizeInBits(BaseVT) == 32) {
      unsigned Idx = cast<ConstantSDNode>(N2)->getValue();
      if (Idx == 0) {
        // Use a movss.
        N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, N1);
        MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
        MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
        std::vector<SDOperand> MaskVec;
        MaskVec.push_back(DAG.getConstant(4, BaseVT));
        for (unsigned i = 1; i <= 3; ++i)
          MaskVec.push_back(DAG.getConstant(i, BaseVT));
        return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, N0, N1,
                           DAG.getNode(ISD::BUILD_VECTOR, MaskVT, MaskVec));
      } else {
        // Use two pinsrw instructions to insert a 32 bit value.
        Idx <<= 1;
        if (MVT::isFloatingPoint(N1.getValueType())) {
          if (N1.getOpcode() == ISD::LOAD) {
            // Just load directly from f32mem to R32.
            N1 = DAG.getLoad(MVT::i32, N1.getOperand(0), N1.getOperand(1),
                             N1.getOperand(2));
          } else {
            N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v4f32, N1);
            N1 = DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32, N1);
            N1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, MVT::i32, N1,
                             DAG.getConstant(0, MVT::i32));
          }
        N0 = DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, N0);
        N0 = DAG.getNode(X86ISD::PINSRW, MVT::v8i16, N0, N1,
                         DAG.getConstant(Idx, MVT::i32));
        N1 = DAG.getNode(ISD::SRL, MVT::i32, N1, DAG.getConstant(16, MVT::i8));
        N0 = DAG.getNode(X86ISD::PINSRW, MVT::v8i16, N0, N1,
                         DAG.getConstant(Idx+1, MVT::i32));
        return DAG.getNode(ISD::BIT_CONVERT, VT, N0);
  case ISD::INTRINSIC_WO_CHAIN: {
    unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getValue();
    switch (IntNo) {
    default: return SDOperand();    // Don't custom lower most intrinsics.
    // Comparison intrinsics.
    case Intrinsic::x86_sse_comieq_ss:
    case Intrinsic::x86_sse_comilt_ss:
    case Intrinsic::x86_sse_comile_ss:
    case Intrinsic::x86_sse_comigt_ss:
    case Intrinsic::x86_sse_comige_ss:
    case Intrinsic::x86_sse_comineq_ss:
    case Intrinsic::x86_sse_ucomieq_ss:
    case Intrinsic::x86_sse_ucomilt_ss:
    case Intrinsic::x86_sse_ucomile_ss:
    case Intrinsic::x86_sse_ucomigt_ss:
    case Intrinsic::x86_sse_ucomige_ss:
    case Intrinsic::x86_sse_ucomineq_ss:
    case Intrinsic::x86_sse2_comieq_sd:
    case Intrinsic::x86_sse2_comilt_sd:
    case Intrinsic::x86_sse2_comile_sd:
    case Intrinsic::x86_sse2_comigt_sd:
    case Intrinsic::x86_sse2_comige_sd:
    case Intrinsic::x86_sse2_comineq_sd:
    case Intrinsic::x86_sse2_ucomieq_sd:
    case Intrinsic::x86_sse2_ucomilt_sd:
    case Intrinsic::x86_sse2_ucomile_sd:
    case Intrinsic::x86_sse2_ucomigt_sd:
    case Intrinsic::x86_sse2_ucomige_sd:
    case Intrinsic::x86_sse2_ucomineq_sd: {
      unsigned Opc = 0;
      ISD::CondCode CC = ISD::SETCC_INVALID;
      switch (IntNo) {
        default: break;
        case Intrinsic::x86_sse_comieq_ss: 
        case Intrinsic::x86_sse2_comieq_sd: 
          Opc = X86ISD::COMI;
          CC = ISD::SETEQ;
          break;
        case Intrinsic::x86_sse_comilt_ss:
        case Intrinsic::x86_sse2_comilt_sd:
          Opc = X86ISD::COMI;
          CC = ISD::SETLT;
          break;
        case Intrinsic::x86_sse_comile_ss:
        case Intrinsic::x86_sse2_comile_sd:
          Opc = X86ISD::COMI;
          CC = ISD::SETLE;
          break;
        case Intrinsic::x86_sse_comigt_ss:
        case Intrinsic::x86_sse2_comigt_sd:
          Opc = X86ISD::COMI;
          CC = ISD::SETGT;
          break;
        case Intrinsic::x86_sse_comige_ss:
        case Intrinsic::x86_sse2_comige_sd:
          Opc = X86ISD::COMI;
          CC = ISD::SETGE;
          break;
        case Intrinsic::x86_sse_comineq_ss:
        case Intrinsic::x86_sse2_comineq_sd:
          Opc = X86ISD::COMI;
          CC = ISD::SETNE;
          break;
        case Intrinsic::x86_sse_ucomieq_ss:
        case Intrinsic::x86_sse2_ucomieq_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETEQ;
          break;
        case Intrinsic::x86_sse_ucomilt_ss:
        case Intrinsic::x86_sse2_ucomilt_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETLT;
          break;
        case Intrinsic::x86_sse_ucomile_ss:
        case Intrinsic::x86_sse2_ucomile_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETLE;
          break;
        case Intrinsic::x86_sse_ucomigt_ss:
        case Intrinsic::x86_sse2_ucomigt_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETGT;
          break;
        case Intrinsic::x86_sse_ucomige_ss:
        case Intrinsic::x86_sse2_ucomige_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETGE;
          break;
        case Intrinsic::x86_sse_ucomineq_ss:
        case Intrinsic::x86_sse2_ucomineq_sd:
          Opc = X86ISD::UCOMI;
          CC = ISD::SETNE;
          break;
      }
      bool Flip;
      unsigned X86CC;
      translateX86CC(CC, true, X86CC, Flip);
      SDOperand Cond = DAG.getNode(Opc, MVT::Flag, Op.getOperand(Flip?2:1),
                                   Op.getOperand(Flip?1:2));
      SDOperand SetCC = DAG.getNode(X86ISD::SETCC, MVT::i8, 
                                    DAG.getConstant(X86CC, MVT::i8), Cond);
      return DAG.getNode(ISD::ANY_EXTEND, MVT::i32, SetCC);
    }
    }
  }

const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
  switch (Opcode) {
  default: return NULL;
  case X86ISD::SHLD:               return "X86ISD::SHLD";
  case X86ISD::SHRD:               return "X86ISD::SHRD";
  case X86ISD::FAND:               return "X86ISD::FAND";
  case X86ISD::FXOR:               return "X86ISD::FXOR";
  case X86ISD::FILD:               return "X86ISD::FILD";
  case X86ISD::FILD_FLAG:          return "X86ISD::FILD_FLAG";
  case X86ISD::FP_TO_INT16_IN_MEM: return "X86ISD::FP_TO_INT16_IN_MEM";
  case X86ISD::FP_TO_INT32_IN_MEM: return "X86ISD::FP_TO_INT32_IN_MEM";
  case X86ISD::FP_TO_INT64_IN_MEM: return "X86ISD::FP_TO_INT64_IN_MEM";
  case X86ISD::FLD:                return "X86ISD::FLD";
Evan Cheng's avatar
Evan Cheng committed
  case X86ISD::FST:                return "X86ISD::FST";
  case X86ISD::FP_GET_RESULT:      return "X86ISD::FP_GET_RESULT";
  case X86ISD::FP_SET_RESULT:      return "X86ISD::FP_SET_RESULT";
  case X86ISD::CALL:               return "X86ISD::CALL";
  case X86ISD::TAILCALL:           return "X86ISD::TAILCALL";
  case X86ISD::RDTSC_DAG:          return "X86ISD::RDTSC_DAG";
  case X86ISD::CMP:                return "X86ISD::CMP";
  case X86ISD::TEST:               return "X86ISD::TEST";
  case X86ISD::COMI:               return "X86ISD::COMI";
  case X86ISD::UCOMI:              return "X86ISD::UCOMI";
  case X86ISD::SETCC:              return "X86ISD::SETCC";
  case X86ISD::CMOV:               return "X86ISD::CMOV";
  case X86ISD::BRCOND:             return "X86ISD::BRCOND";
  case X86ISD::RET_FLAG:           return "X86ISD::RET_FLAG";
Evan Cheng's avatar
Evan Cheng committed
  case X86ISD::REP_STOS:           return "X86ISD::REP_STOS";
  case X86ISD::REP_MOVS:           return "X86ISD::REP_MOVS";
  case X86ISD::LOAD_PACK:          return "X86ISD::LOAD_PACK";
Evan Cheng's avatar
Evan Cheng committed
  case X86ISD::GlobalBaseReg:      return "X86ISD::GlobalBaseReg";
  case X86ISD::Wrapper:            return "X86ISD::Wrapper";
  case X86ISD::S2VEC:              return "X86ISD::S2VEC";
  case X86ISD::ZEXT_S2VEC:         return "X86ISD::ZEXT_S2VEC";
  case X86ISD::PEXTRW:             return "X86ISD::PEXTRW";
  case X86ISD::PINSRW:             return "X86ISD::PINSRW";
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;

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 constriant letter
    case 'r':   // GENERAL_REGS
    case 'R':   // LEGACY_REGS
      return make_vector<unsigned>(X86::EAX, X86::EBX, X86::ECX, X86::EDX,
                                   X86::ESI, X86::EDI, X86::EBP, X86::ESP, 0);
    case 'l':   // INDEX_REGS
      return make_vector<unsigned>(X86::EAX, X86::EBX, X86::ECX, X86::EDX,
                                   X86::ESI, X86::EDI, X86::EBP, 0);
    case 'q':   // Q_REGS (GENERAL_REGS in 64-bit mode)
    case 'Q':   // Q_REGS
      return make_vector<unsigned>(X86::EAX, X86::EBX, X86::ECX, X86::EDX, 0);
    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>();
Evan Cheng's avatar
Evan Cheng committed

/// isLegalAddressImmediate - Return true if the integer value or
/// GlobalValue can be used as the offset of the target addressing mode.
bool X86TargetLowering::isLegalAddressImmediate(int64_t V) const {
  // X86 allows a sign-extended 32-bit immediate field.
  return (V > -(1LL << 32) && V < (1LL << 32)-1);
}

bool X86TargetLowering::isLegalAddressImmediate(GlobalValue *GV) const {
Evan Cheng's avatar
Evan Cheng committed
  if (Subtarget->isTargetDarwin()) {
Evan Cheng's avatar
Evan Cheng committed
    Reloc::Model RModel = getTargetMachine().getRelocationModel();
    if (RModel == Reloc::Static)
      return true;
    else if (RModel == Reloc::DynamicNoPIC)
Evan Cheng's avatar
Evan Cheng committed
      return !DarwinGVRequiresExtraLoad(GV);
Evan Cheng's avatar
Evan Cheng committed
    else
      return false;
  } else
    return true;
}

/// isShuffleMaskLegal - Targets can use this to indicate that they only
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
/// By default, if a target supports the VECTOR_SHUFFLE node, all mask values
/// are assumed to be legal.
bool
X86TargetLowering::isShuffleMaskLegal(SDOperand Mask, MVT::ValueType VT) const {
  // Only do shuffles on 128-bit vector types for now.
  if (MVT::getSizeInBits(VT) == 64) return false;
  return (Mask.Val->getNumOperands() <= 4 ||
          isSplatMask(Mask.Val)  ||
Evan Cheng's avatar
Evan Cheng committed
          X86::isUNPCKLMask(Mask.Val) ||
          X86::isUNPCKL_v_undef_Mask(Mask.Val) ||
          X86::isUNPCKHMask(Mask.Val));