aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2006-03-28 20:28:38 +0000
committerChris Lattner <sabre@nondot.org>2006-03-28 20:28:38 +0000
commitd7648c89343c62e154a7d374485dc93a9dc49d54 (patch)
treec1373525ca8ef600d06612425761467f7e84313d /lib/CodeGen/SelectionDAG/DAGCombiner.cpp
parent5b2316e2b06e0fb6aea31d9d3eb61376b40c23a6 (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.cpp86
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!");