diff options
Diffstat (limited to 'lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp')
| -rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp | 349 | 
1 files changed, 268 insertions, 81 deletions
| diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp index 3fb2d9bdf55e..507e7ffb1d45 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -37,12 +37,12 @@ class VectorLegalizer {    const TargetLowering &TLI;    bool Changed; // Keep track of whether anything changed -  /// LegalizedNodes - For nodes that are of legal width, and that have more -  /// than one use, this map indicates what regularized operand to use.  This -  /// allows us to avoid legalizing the same thing more than once. +  /// For nodes that are of legal width, and that have more than one use, this +  /// map indicates what regularized operand to use.  This allows us to avoid +  /// legalizing the same thing more than once.    SmallDenseMap<SDValue, SDValue, 64> LegalizedNodes; -  // Adds a node to the translation cache +  /// \brief Adds a node to the translation cache.    void AddLegalizedOperand(SDValue From, SDValue To) {      LegalizedNodes.insert(std::make_pair(From, To));      // If someone requests legalization of the new node, return itself. @@ -50,35 +50,81 @@ class VectorLegalizer {        LegalizedNodes.insert(std::make_pair(To, To));    } -  // Legalizes the given node +  /// \brief Legalizes the given node.    SDValue LegalizeOp(SDValue Op); -  // Assuming the node is legal, "legalize" the results + +  /// \brief Assuming the node is legal, "legalize" the results.    SDValue TranslateLegalizeResults(SDValue Op, SDValue Result); -  // Implements unrolling a VSETCC. + +  /// \brief Implements unrolling a VSETCC.    SDValue UnrollVSETCC(SDValue Op); -  // Implements expansion for FNEG; falls back to UnrollVectorOp if FSUB -  // isn't legal. -  // Implements expansion for UINT_TO_FLOAT; falls back to UnrollVectorOp if -  // SINT_TO_FLOAT and SHR on vectors isn't legal. + +  /// \brief Implement expand-based legalization of vector operations. +  /// +  /// This is just a high-level routine to dispatch to specific code paths for +  /// operations to legalize them. +  SDValue Expand(SDValue Op); + +  /// \brief Implements expansion for FNEG; falls back to UnrollVectorOp if +  /// FSUB isn't legal. +  /// +  /// Implements expansion for UINT_TO_FLOAT; falls back to UnrollVectorOp if +  /// SINT_TO_FLOAT and SHR on vectors isn't legal.    SDValue ExpandUINT_TO_FLOAT(SDValue Op); -  // Implement expansion for SIGN_EXTEND_INREG using SRL and SRA. + +  /// \brief Implement expansion for SIGN_EXTEND_INREG using SRL and SRA.    SDValue ExpandSEXTINREG(SDValue Op); -  // Implement vselect in terms of XOR, AND, OR when blend is not supported -  // by the target. + +  /// \brief Implement expansion for ANY_EXTEND_VECTOR_INREG. +  /// +  /// Shuffles the low lanes of the operand into place and bitcasts to the proper +  /// type. The contents of the bits in the extended part of each element are +  /// undef. +  SDValue ExpandANY_EXTEND_VECTOR_INREG(SDValue Op); + +  /// \brief Implement expansion for SIGN_EXTEND_VECTOR_INREG. +  /// +  /// Shuffles the low lanes of the operand into place, bitcasts to the proper +  /// type, then shifts left and arithmetic shifts right to introduce a sign +  /// extension. +  SDValue ExpandSIGN_EXTEND_VECTOR_INREG(SDValue Op); + +  /// \brief Implement expansion for ZERO_EXTEND_VECTOR_INREG. +  /// +  /// Shuffles the low lanes of the operand into place and blends zeros into +  /// the remaining lanes, finally bitcasting to the proper type. +  SDValue ExpandZERO_EXTEND_VECTOR_INREG(SDValue Op); + +  /// \brief Expand bswap of vectors into a shuffle if legal. +  SDValue ExpandBSWAP(SDValue Op); + +  /// \brief Implement vselect in terms of XOR, AND, OR when blend is not +  /// supported by the target.    SDValue ExpandVSELECT(SDValue Op);    SDValue ExpandSELECT(SDValue Op);    SDValue ExpandLoad(SDValue Op);    SDValue ExpandStore(SDValue Op);    SDValue ExpandFNEG(SDValue Op); -  // Implements vector promotion; this is essentially just bitcasting the -  // operands to a different type and bitcasting the result back to the -  // original type. -  SDValue PromoteVectorOp(SDValue Op); -  // Implements [SU]INT_TO_FP vector promotion; this is a [zs]ext of the input -  // operand to the next size up. -  SDValue PromoteVectorOpINT_TO_FP(SDValue Op); - -  public: + +  /// \brief Implements vector promotion. +  /// +  /// This is essentially just bitcasting the operands to a different type and +  /// bitcasting the result back to the original type. +  SDValue Promote(SDValue Op); + +  /// \brief Implements [SU]INT_TO_FP vector promotion. +  /// +  /// This is a [zs]ext of the input operand to the next size up. +  SDValue PromoteINT_TO_FP(SDValue Op); + +  /// \brief Implements FP_TO_[SU]INT vector promotion of the result type. +  /// +  /// It is promoted to the next size up integer type.  The result is then +  /// truncated back to the original type. +  SDValue PromoteFP_TO_INT(SDValue Op, bool isSigned); + +public: +  /// \brief Begin legalizer the vector operations in the DAG.    bool Run();    VectorLegalizer(SelectionDAG& dag) :        DAG(dag), TLI(dag.getTargetLoweringInfo()), Changed(false) {} @@ -88,7 +134,7 @@ bool VectorLegalizer::Run() {    // Before we start legalizing vector nodes, check if there are any vectors.    bool HasVectors = false;    for (SelectionDAG::allnodes_iterator I = DAG.allnodes_begin(), -       E = prior(DAG.allnodes_end()); I != llvm::next(E); ++I) { +       E = std::prev(DAG.allnodes_end()); I != std::next(E); ++I) {      // Check if the values of the nodes contain vectors. We don't need to check      // the operands because we are going to check their values at some point.      for (SDNode::value_iterator J = I->value_begin(), E = I->value_end(); @@ -112,7 +158,7 @@ bool VectorLegalizer::Run() {    // node is only legalized after all of its operands are legalized.    DAG.AssignTopologicalOrder();    for (SelectionDAG::allnodes_iterator I = DAG.allnodes_begin(), -       E = prior(DAG.allnodes_end()); I != llvm::next(E); ++I) +       E = std::prev(DAG.allnodes_end()); I != std::next(E); ++I)      LegalizeOp(SDValue(I, 0));    // Finally, it's possible the root changed.  Get the new root. @@ -148,8 +194,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {    for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i)      Ops.push_back(LegalizeOp(Node->getOperand(i))); -  SDValue Result = -    SDValue(DAG.UpdateNodeOperands(Op.getNode(), Ops.data(), Ops.size()), 0); +  SDValue Result = SDValue(DAG.UpdateNodeOperands(Op.getNode(), Ops), 0);    if (Op.getOpcode() == ISD::LOAD) {      LoadSDNode *LD = cast<LoadSDNode>(Op.getNode()); @@ -249,6 +294,9 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {    case ISD::FP_EXTEND:    case ISD::FMA:    case ISD::SIGN_EXTEND_INREG: +  case ISD::ANY_EXTEND_VECTOR_INREG: +  case ISD::SIGN_EXTEND_VECTOR_INREG: +  case ISD::ZERO_EXTEND_VECTOR_INREG:      QueryType = Node->getValueType(0);      break;    case ISD::FP_ROUND_INREG: @@ -262,21 +310,11 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {    switch (TLI.getOperationAction(Node->getOpcode(), QueryType)) {    case TargetLowering::Promote: -    switch (Op.getOpcode()) { -    default: -      // "Promote" the operation by bitcasting -      Result = PromoteVectorOp(Op); -      Changed = true; -      break; -    case ISD::SINT_TO_FP: -    case ISD::UINT_TO_FP: -      // "Promote" the operation by extending the operand. -      Result = PromoteVectorOpINT_TO_FP(Op); -      Changed = true; -      break; -    } +    Result = Promote(Op); +    Changed = true; +    break; +  case TargetLowering::Legal:      break; -  case TargetLowering::Legal: break;    case TargetLowering::Custom: {      SDValue Tmp1 = TLI.LowerOperation(Op, DAG);      if (Tmp1.getNode()) { @@ -286,21 +324,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {      // FALL THROUGH    }    case TargetLowering::Expand: -    if (Node->getOpcode() == ISD::SIGN_EXTEND_INREG) -      Result = ExpandSEXTINREG(Op); -    else if (Node->getOpcode() == ISD::VSELECT) -      Result = ExpandVSELECT(Op); -    else if (Node->getOpcode() == ISD::SELECT) -      Result = ExpandSELECT(Op); -    else if (Node->getOpcode() == ISD::UINT_TO_FP) -      Result = ExpandUINT_TO_FLOAT(Op); -    else if (Node->getOpcode() == ISD::FNEG) -      Result = ExpandFNEG(Op); -    else if (Node->getOpcode() == ISD::SETCC) -      Result = UnrollVSETCC(Op); -    else -      Result = DAG.UnrollVectorOp(Op.getNode()); -    break; +    Result = Expand(Op);    }    // Make sure that the generated code is itself legal. @@ -315,10 +339,23 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {    return Result;  } -SDValue VectorLegalizer::PromoteVectorOp(SDValue Op) { -  // Vector "promotion" is basically just bitcasting and doing the operation -  // in a different type.  For example, x86 promotes ISD::AND on v2i32 to -  // v1i64. +SDValue VectorLegalizer::Promote(SDValue Op) { +  // For a few operations there is a specific concept for promotion based on +  // the operand's type. +  switch (Op.getOpcode()) { +  case ISD::SINT_TO_FP: +  case ISD::UINT_TO_FP: +    // "Promote" the operation by extending the operand. +    return PromoteINT_TO_FP(Op); +  case ISD::FP_TO_UINT: +  case ISD::FP_TO_SINT: +    // Promote the operation by extending the operand. +    return PromoteFP_TO_INT(Op, Op->getOpcode() == ISD::FP_TO_SINT); +  } + +  // The rest of the time, vector "promotion" is basically just bitcasting and +  // doing the operation in a different type.  For example, x86 promotes +  // ISD::AND on v2i32 to v1i64.    MVT VT = Op.getSimpleValueType();    assert(Op.getNode()->getNumValues() == 1 &&           "Can't promote a vector with multiple results!"); @@ -333,12 +370,12 @@ SDValue VectorLegalizer::PromoteVectorOp(SDValue Op) {        Operands[j] = Op.getOperand(j);    } -  Op = DAG.getNode(Op.getOpcode(), dl, NVT, &Operands[0], Operands.size()); +  Op = DAG.getNode(Op.getOpcode(), dl, NVT, Operands);    return DAG.getNode(ISD::BITCAST, dl, VT, Op);  } -SDValue VectorLegalizer::PromoteVectorOpINT_TO_FP(SDValue Op) { +SDValue VectorLegalizer::PromoteINT_TO_FP(SDValue Op) {    // INT_TO_FP operations may require the input operand be promoted even    // when the type is otherwise legal.    EVT VT = Op.getOperand(0).getValueType(); @@ -352,14 +389,9 @@ SDValue VectorLegalizer::PromoteVectorOpINT_TO_FP(SDValue Op) {    //    // Increase the bitwidth of the element to the next pow-of-two    // (which is greater than 8 bits). -  unsigned NumElts = VT.getVectorNumElements(); -  EVT EltVT = VT.getVectorElementType(); -  EltVT = EVT::getIntegerVT(*DAG.getContext(), 2 * EltVT.getSizeInBits()); -  assert(EltVT.isSimple() && "Promoting to a non-simple vector type!"); - -  // Build a new vector type and check if it is legal. -  MVT NVT = MVT::getVectorVT(EltVT.getSimpleVT(), NumElts); +  EVT NVT = VT.widenIntegerVectorElementType(*DAG.getContext()); +  assert(NVT.isSimple() && "Promoting to a non-simple vector type!");    SDLoc dl(Op);    SmallVector<SDValue, 4> Operands(Op.getNumOperands()); @@ -372,8 +404,36 @@ SDValue VectorLegalizer::PromoteVectorOpINT_TO_FP(SDValue Op) {        Operands[j] = Op.getOperand(j);    } -  return DAG.getNode(Op.getOpcode(), dl, Op.getValueType(), &Operands[0], -                     Operands.size()); +  return DAG.getNode(Op.getOpcode(), dl, Op.getValueType(), Operands); +} + +// For FP_TO_INT we promote the result type to a vector type with wider +// elements and then truncate the result.  This is different from the default +// PromoteVector which uses bitcast to promote thus assumning that the +// promoted vector type has the same overall size. +SDValue VectorLegalizer::PromoteFP_TO_INT(SDValue Op, bool isSigned) { +  assert(Op.getNode()->getNumValues() == 1 && +         "Can't promote a vector with multiple results!"); +  EVT VT = Op.getValueType(); + +  EVT NewVT; +  unsigned NewOpc; +  while (1) { +    NewVT = VT.widenIntegerVectorElementType(*DAG.getContext()); +    assert(NewVT.isSimple() && "Promoting to a non-simple vector type!"); +    if (TLI.isOperationLegalOrCustom(ISD::FP_TO_SINT, NewVT)) { +      NewOpc = ISD::FP_TO_SINT; +      break; +    } +    if (!isSigned && TLI.isOperationLegalOrCustom(ISD::FP_TO_UINT, NewVT)) { +      NewOpc = ISD::FP_TO_UINT; +      break; +    } +  } + +  SDLoc loc(Op); +  SDValue promoted  = DAG.getNode(NewOpc, SDLoc(Op), NewVT, Op.getOperand(0)); +  return DAG.getNode(ISD::TRUNCATE, SDLoc(Op), VT, promoted);  } @@ -512,10 +572,9 @@ SDValue VectorLegalizer::ExpandLoad(SDValue Op) {      }    } -  SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, -            &LoadChains[0], LoadChains.size()); +  SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, LoadChains);    SDValue Value = DAG.getNode(ISD::BUILD_VECTOR, dl, -            Op.getNode()->getValueType(0), &Vals[0], Vals.size()); +                              Op.getNode()->getValueType(0), Vals);    AddLegalizedOperand(Op.getValue(0), Value);    AddLegalizedOperand(Op.getValue(1), NewChain); @@ -569,12 +628,38 @@ SDValue VectorLegalizer::ExpandStore(SDValue Op) {      Stores.push_back(Store);    } -  SDValue TF =  DAG.getNode(ISD::TokenFactor, dl, MVT::Other, -                            &Stores[0], Stores.size()); +  SDValue TF =  DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores);    AddLegalizedOperand(Op, TF);    return TF;  } +SDValue VectorLegalizer::Expand(SDValue Op) { +  switch (Op->getOpcode()) { +  case ISD::SIGN_EXTEND_INREG: +    return ExpandSEXTINREG(Op); +  case ISD::ANY_EXTEND_VECTOR_INREG: +    return ExpandANY_EXTEND_VECTOR_INREG(Op); +  case ISD::SIGN_EXTEND_VECTOR_INREG: +    return ExpandSIGN_EXTEND_VECTOR_INREG(Op); +  case ISD::ZERO_EXTEND_VECTOR_INREG: +    return ExpandZERO_EXTEND_VECTOR_INREG(Op); +  case ISD::BSWAP: +    return ExpandBSWAP(Op); +  case ISD::VSELECT: +    return ExpandVSELECT(Op); +  case ISD::SELECT: +    return ExpandSELECT(Op); +  case ISD::UINT_TO_FP: +    return ExpandUINT_TO_FLOAT(Op); +  case ISD::FNEG: +    return ExpandFNEG(Op); +  case ISD::SETCC: +    return UnrollVSETCC(Op); +  default: +    return DAG.UnrollVectorOp(Op.getNode()); +  } +} +  SDValue VectorLegalizer::ExpandSELECT(SDValue Op) {    // Lower a select instruction where the condition is a scalar and the    // operands are vectors. Lower this select to VSELECT and implement it @@ -614,7 +699,7 @@ SDValue VectorLegalizer::ExpandSELECT(SDValue Op) {    // Broadcast the mask so that the entire vector is all-one or all zero.    SmallVector<SDValue, 8> Ops(NumElem, Mask); -  Mask = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskTy, &Ops[0], Ops.size()); +  Mask = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskTy, Ops);    // Bitcast the operands to be the same type as the mask.    // This is needed when we select between FP types because @@ -652,6 +737,108 @@ SDValue VectorLegalizer::ExpandSEXTINREG(SDValue Op) {    return DAG.getNode(ISD::SRA, DL, VT, Op, ShiftSz);  } +// Generically expand a vector anyext in register to a shuffle of the relevant +// lanes into the appropriate locations, with other lanes left undef. +SDValue VectorLegalizer::ExpandANY_EXTEND_VECTOR_INREG(SDValue Op) { +  SDLoc DL(Op); +  EVT VT = Op.getValueType(); +  int NumElements = VT.getVectorNumElements(); +  SDValue Src = Op.getOperand(0); +  EVT SrcVT = Src.getValueType(); +  int NumSrcElements = SrcVT.getVectorNumElements(); + +  // Build a base mask of undef shuffles. +  SmallVector<int, 16> ShuffleMask; +  ShuffleMask.resize(NumSrcElements, -1); + +  // Place the extended lanes into the correct locations. +  int ExtLaneScale = NumSrcElements / NumElements; +  int EndianOffset = TLI.isBigEndian() ? ExtLaneScale - 1 : 0; +  for (int i = 0; i < NumElements; ++i) +    ShuffleMask[i * ExtLaneScale + EndianOffset] = i; + +  return DAG.getNode( +      ISD::BITCAST, DL, VT, +      DAG.getVectorShuffle(SrcVT, DL, Src, DAG.getUNDEF(SrcVT), ShuffleMask)); +} + +SDValue VectorLegalizer::ExpandSIGN_EXTEND_VECTOR_INREG(SDValue Op) { +  SDLoc DL(Op); +  EVT VT = Op.getValueType(); +  SDValue Src = Op.getOperand(0); +  EVT SrcVT = Src.getValueType(); + +  // First build an any-extend node which can be legalized above when we +  // recurse through it. +  Op = DAG.getAnyExtendVectorInReg(Src, DL, VT); + +  // Now we need sign extend. Do this by shifting the elements. Even if these +  // aren't legal operations, they have a better chance of being legalized +  // without full scalarization than the sign extension does. +  unsigned EltWidth = VT.getVectorElementType().getSizeInBits(); +  unsigned SrcEltWidth = SrcVT.getVectorElementType().getSizeInBits(); +  SDValue ShiftAmount = DAG.getConstant(EltWidth - SrcEltWidth, VT); +  return DAG.getNode(ISD::SRA, DL, VT, +                     DAG.getNode(ISD::SHL, DL, VT, Op, ShiftAmount), +                     ShiftAmount); +} + +// Generically expand a vector zext in register to a shuffle of the relevant +// lanes into the appropriate locations, a blend of zero into the high bits, +// and a bitcast to the wider element type. +SDValue VectorLegalizer::ExpandZERO_EXTEND_VECTOR_INREG(SDValue Op) { +  SDLoc DL(Op); +  EVT VT = Op.getValueType(); +  int NumElements = VT.getVectorNumElements(); +  SDValue Src = Op.getOperand(0); +  EVT SrcVT = Src.getValueType(); +  int NumSrcElements = SrcVT.getVectorNumElements(); + +  // Build up a zero vector to blend into this one. +  EVT SrcScalarVT = SrcVT.getScalarType(); +  SDValue ScalarZero = DAG.getTargetConstant(0, SrcScalarVT); +  SmallVector<SDValue, 4> BuildVectorOperands(NumSrcElements, ScalarZero); +  SDValue Zero = DAG.getNode(ISD::BUILD_VECTOR, DL, SrcVT, BuildVectorOperands); + +  // Shuffle the incoming lanes into the correct position, and pull all other +  // lanes from the zero vector. +  SmallVector<int, 16> ShuffleMask; +  ShuffleMask.reserve(NumSrcElements); +  for (int i = 0; i < NumSrcElements; ++i) +    ShuffleMask.push_back(i); + +  int ExtLaneScale = NumSrcElements / NumElements; +  int EndianOffset = TLI.isBigEndian() ? ExtLaneScale - 1 : 0; +  for (int i = 0; i < NumElements; ++i) +    ShuffleMask[i * ExtLaneScale + EndianOffset] = NumSrcElements + i; + +  return DAG.getNode(ISD::BITCAST, DL, VT, +                     DAG.getVectorShuffle(SrcVT, DL, Zero, Src, ShuffleMask)); +} + +SDValue VectorLegalizer::ExpandBSWAP(SDValue Op) { +  EVT VT = Op.getValueType(); + +  // Generate a byte wise shuffle mask for the BSWAP. +  SmallVector<int, 16> ShuffleMask; +  int ScalarSizeInBytes = VT.getScalarSizeInBits() / 8; +  for (int I = 0, E = VT.getVectorNumElements(); I != E; ++I) +    for (int J = ScalarSizeInBytes - 1; J >= 0; --J) +      ShuffleMask.push_back((I * ScalarSizeInBytes) + J); + +  EVT ByteVT = EVT::getVectorVT(*DAG.getContext(), MVT::i8, ShuffleMask.size()); + +  // Only emit a shuffle if the mask is legal. +  if (!TLI.isShuffleMaskLegal(ShuffleMask, ByteVT)) +    return DAG.UnrollVectorOp(Op.getNode()); + +  SDLoc DL(Op); +  Op = DAG.getNode(ISD::BITCAST, DL, ByteVT, Op.getOperand(0)); +  Op = DAG.getVectorShuffle(ByteVT, DL, Op, DAG.getUNDEF(ByteVT), +                            ShuffleMask.data()); +  return DAG.getNode(ISD::BITCAST, DL, VT, Op); +} +  SDValue VectorLegalizer::ExpandVSELECT(SDValue Op) {    // Implement VSELECT in terms of XOR, AND, OR    // on platforms which do not support blend natively. @@ -672,9 +859,9 @@ SDValue VectorLegalizer::ExpandVSELECT(SDValue Op) {    // FIXME: Sign extend 1 to all ones if thats legal on the target.    if (TLI.getOperationAction(ISD::AND, VT) == TargetLowering::Expand ||        TLI.getOperationAction(ISD::XOR, VT) == TargetLowering::Expand || -      TLI.getOperationAction(ISD::OR,  VT) == TargetLowering::Expand || -      TLI.getBooleanContents(true) != -      TargetLowering::ZeroOrNegativeOneBooleanContent) +      TLI.getOperationAction(ISD::OR, VT) == TargetLowering::Expand || +      TLI.getBooleanContents(Op1.getValueType()) != +          TargetLowering::ZeroOrNegativeOneBooleanContent)      return DAG.UnrollVectorOp(Op.getNode());    // If the mask and the type are different sizes, unroll the vector op. This @@ -769,7 +956,7 @@ SDValue VectorLegalizer::UnrollVSETCC(SDValue Op) {                                             (EltVT.getSizeInBits()), EltVT),                             DAG.getConstant(0, EltVT));    } -  return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, &Ops[0], NumElems); +  return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, Ops);  }  } | 
