Turn a series of extract_element's feeding a build_vector into a

vector_shuffle node.  For this:

void test(__m128 *res, __m128 *A, __m128 *B) {
  *res = _mm_unpacklo_ps(*A, *B);
}

we now produce this code:

_test:
        movl 8(%esp), %eax
        movaps (%eax), %xmm0
        movl 12(%esp), %eax
        unpcklps (%eax), %xmm0
        movl 4(%esp), %eax
        movaps %xmm0, (%eax)
        ret

instead of this:

_test:
        subl $76, %esp
        movl 88(%esp), %eax
        movaps (%eax), %xmm0
        movaps %xmm0, (%esp)
        movaps %xmm0, 32(%esp)
        movss 4(%esp), %xmm0
        movss 32(%esp), %xmm1
        unpcklps %xmm0, %xmm1
        movl 84(%esp), %eax
        movaps (%eax), %xmm0
        movaps %xmm0, 16(%esp)
        movaps %xmm0, 48(%esp)
        movss 20(%esp), %xmm0
        movss 48(%esp), %xmm2
        unpcklps %xmm0, %xmm2
        unpcklps %xmm1, %xmm2
        movl 80(%esp), %eax
        movaps %xmm2, (%eax)
        addl $76, %esp
        ret

GCC produces this (with -fomit-frame-pointer):

_test:
        subl    $12, %esp
        movl    20(%esp), %eax
        movaps  (%eax), %xmm0
        movl    24(%esp), %eax
        unpcklps        (%eax), %xmm0
        movl    16(%esp), %eax
        movaps  %xmm0, (%eax)
        addl    $12, %esp
        ret


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@27233 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-03-28 20:28:38 +00:00
parent 5b2316e2b0
commit d7648c8934

View File

@ -211,6 +211,7 @@ namespace {
SDOperand visitSTORE(SDNode *N); SDOperand visitSTORE(SDNode *N);
SDOperand visitINSERT_VECTOR_ELT(SDNode *N); SDOperand visitINSERT_VECTOR_ELT(SDNode *N);
SDOperand visitVINSERT_VECTOR_ELT(SDNode *N); SDOperand visitVINSERT_VECTOR_ELT(SDNode *N);
SDOperand visitVBUILD_VECTOR(SDNode *N);
SDOperand ReassociateOps(unsigned Opc, SDOperand LHS, SDOperand RHS); SDOperand ReassociateOps(unsigned Opc, SDOperand LHS, SDOperand RHS);
@ -644,6 +645,7 @@ SDOperand DAGCombiner::visit(SDNode *N) {
case ISD::STORE: return visitSTORE(N); case ISD::STORE: return visitSTORE(N);
case ISD::INSERT_VECTOR_ELT: return visitINSERT_VECTOR_ELT(N); case ISD::INSERT_VECTOR_ELT: return visitINSERT_VECTOR_ELT(N);
case ISD::VINSERT_VECTOR_ELT: return visitVINSERT_VECTOR_ELT(N); case ISD::VINSERT_VECTOR_ELT: return visitVINSERT_VECTOR_ELT(N);
case ISD::VBUILD_VECTOR: return visitVBUILD_VECTOR(N);
} }
return SDOperand(); return SDOperand();
} }
@ -2341,6 +2343,90 @@ SDOperand DAGCombiner::visitVINSERT_VECTOR_ELT(SDNode *N) {
return SDOperand(); return SDOperand();
} }
SDOperand DAGCombiner::visitVBUILD_VECTOR(SDNode *N) {
unsigned NumInScalars = N->getNumOperands()-2;
SDOperand NumElts = N->getOperand(NumInScalars);
SDOperand EltType = N->getOperand(NumInScalars+1);
// Check to see if this is a VBUILD_VECTOR of a bunch of VEXTRACT_VECTOR_ELT
// operations. If so, and if the EXTRACT_ELT vector inputs come from at most
// two distinct vectors, turn this into a shuffle node.
SDOperand VecIn1, VecIn2;
for (unsigned i = 0; i != NumInScalars; ++i) {
// Ignore undef inputs.
if (N->getOperand(i).getOpcode() == ISD::UNDEF) continue;
// If this input is something other than a VEXTRACT_VECTOR_ELT with a
// constant index, bail out.
if (N->getOperand(i).getOpcode() != ISD::VEXTRACT_VECTOR_ELT ||
!isa<ConstantSDNode>(N->getOperand(i).getOperand(1))) {
VecIn1 = VecIn2 = SDOperand(0, 0);
break;
}
// If the input vector type disagrees with the result of the vbuild_vector,
// we can't make a shuffle.
SDOperand ExtractedFromVec = N->getOperand(i).getOperand(0);
if (*(ExtractedFromVec.Val->op_end()-2) != NumElts ||
*(ExtractedFromVec.Val->op_end()-1) != EltType) {
VecIn1 = VecIn2 = SDOperand(0, 0);
break;
}
// Otherwise, remember this. We allow up to two distinct input vectors.
if (ExtractedFromVec == VecIn1 || ExtractedFromVec == VecIn2)
continue;
if (VecIn1.Val == 0) {
VecIn1 = ExtractedFromVec;
} else if (VecIn2.Val == 0) {
VecIn2 = ExtractedFromVec;
} else {
// Too many inputs.
VecIn1 = VecIn2 = SDOperand(0, 0);
break;
}
}
// If everything is good, we can make a shuffle operation.
if (VecIn1.Val) {
std::vector<SDOperand> BuildVecIndices;
for (unsigned i = 0; i != NumInScalars; ++i) {
if (N->getOperand(i).getOpcode() == ISD::UNDEF) {
BuildVecIndices.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
continue;
}
SDOperand Extract = N->getOperand(i);
// If extracting from the first vector, just use the index directly.
if (Extract.getOperand(0) == VecIn1) {
BuildVecIndices.push_back(Extract.getOperand(1));
continue;
}
// Otherwise, use InIdx + VecSize
unsigned Idx = cast<ConstantSDNode>(Extract.getOperand(1))->getValue();
BuildVecIndices.push_back(DAG.getConstant(Idx+NumInScalars, MVT::i32));
}
// Add count and size info.
BuildVecIndices.push_back(NumElts);
BuildVecIndices.push_back(DAG.getValueType(MVT::i32));
// Return the new VVECTOR_SHUFFLE node.
std::vector<SDOperand> Ops;
Ops.push_back(VecIn1);
Ops.push_back(VecIn2.Val ? VecIn2 : VecIn1); // Use V1 twice if no V2.
Ops.push_back(DAG.getNode(ISD::VBUILD_VECTOR,MVT::Vector, BuildVecIndices));
Ops.push_back(NumElts);
Ops.push_back(EltType);
return DAG.getNode(ISD::VVECTOR_SHUFFLE, MVT::Vector, Ops);
}
return SDOperand();
}
SDOperand DAGCombiner::SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2){ SDOperand DAGCombiner::SimplifySelect(SDOperand N0, SDOperand N1, SDOperand N2){
assert(N0.getOpcode() ==ISD::SETCC && "First argument must be a SetCC node!"); assert(N0.getOpcode() ==ISD::SETCC && "First argument must be a SetCC node!");