diff options
author | Chris Lattner <sabre@nondot.org> | 2006-03-28 20:28:38 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2006-03-28 20:28:38 +0000 |
commit | d7648c89343c62e154a7d374485dc93a9dc49d54 (patch) | |
tree | c1373525ca8ef600d06612425761467f7e84313d /lib/CodeGen/SelectionDAG/DAGCombiner.cpp | |
parent | 5b2316e2b06e0fb6aea31d9d3eb61376b40c23a6 (diff) |
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
Diffstat (limited to 'lib/CodeGen/SelectionDAG/DAGCombiner.cpp')
-rw-r--r-- | lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 424942b3e9..16952a7bdb 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -211,6 +211,7 @@ namespace { SDOperand visitSTORE(SDNode *N); SDOperand visitINSERT_VECTOR_ELT(SDNode *N); SDOperand visitVINSERT_VECTOR_ELT(SDNode *N); + SDOperand visitVBUILD_VECTOR(SDNode *N); 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::INSERT_VECTOR_ELT: return visitINSERT_VECTOR_ELT(N); case ISD::VINSERT_VECTOR_ELT: return visitVINSERT_VECTOR_ELT(N); + case ISD::VBUILD_VECTOR: return visitVBUILD_VECTOR(N); } return SDOperand(); } @@ -2341,6 +2343,90 @@ SDOperand DAGCombiner::visitVINSERT_VECTOR_ELT(SDNode *N) { 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){ assert(N0.getOpcode() ==ISD::SETCC && "First argument must be a SetCC node!"); |