From: Chris Lattner Date: Tue, 28 Mar 2006 20:28:38 +0000 (+0000) Subject: Turn a series of extract_element's feeding a build_vector into a X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=d7648c89343c62e154a7d374485dc93a9dc49d54;p=oota-llvm.git 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 --- diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 424942b3e9b..16952a7bdb2 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(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 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(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 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!");