Improved shuffle normalization to avoid using extract/build when we

can extract using different indexes for two vectors. Added a few tests
for vector shuffles.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59399 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Mon P Wang 2008-11-16 05:06:27 +00:00
parent 29cd5ba621
commit c7849c22f4
4 changed files with 203 additions and 97 deletions

View File

@ -2292,8 +2292,8 @@ void SelectionDAGLowering::visitExtractElement(User &I) {
// Utility for visitShuffleVector - Returns true if the mask is mask starting // Utility for visitShuffleVector - Returns true if the mask is mask starting
// from SIndx and increasing to the element length (undefs are allowed). // from SIndx and increasing to the element length (undefs are allowed).
static bool SequentialMask(SDValue Mask, unsigned SIndx) { static bool SequentialMask(SDValue Mask, unsigned SIndx) {
unsigned NumElems = Mask.getNumOperands(); unsigned MaskNumElts = Mask.getNumOperands();
for (unsigned i = 0; i != NumElems; ++i) { for (unsigned i = 0; i != MaskNumElts; ++i) {
if (Mask.getOperand(i).getOpcode() != ISD::UNDEF) { if (Mask.getOperand(i).getOpcode() != ISD::UNDEF) {
unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue();
if (Idx != i + SIndx) if (Idx != i + SIndx)
@ -2304,161 +2304,187 @@ static bool SequentialMask(SDValue Mask, unsigned SIndx) {
} }
void SelectionDAGLowering::visitShuffleVector(User &I) { void SelectionDAGLowering::visitShuffleVector(User &I) {
SDValue V1 = getValue(I.getOperand(0)); SDValue Srcs[2];
SDValue V2 = getValue(I.getOperand(1)); Srcs[0] = getValue(I.getOperand(0));
Srcs[1] = getValue(I.getOperand(1));
SDValue Mask = getValue(I.getOperand(2)); SDValue Mask = getValue(I.getOperand(2));
MVT VT = TLI.getValueType(I.getType()); MVT VT = TLI.getValueType(I.getType());
MVT VT1 = V1.getValueType(); MVT SrcVT = Srcs[0].getValueType();
unsigned MaskNumElts = Mask.getNumOperands(); int MaskNumElts = Mask.getNumOperands();
unsigned Src1NumElts = VT1.getVectorNumElements(); int SrcNumElts = SrcVT.getVectorNumElements();
if (Src1NumElts == MaskNumElts) { if (SrcNumElts == MaskNumElts) {
setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, Srcs[0], Srcs[1], Mask));
return; return;
} }
// Normalize the shuffle vector since mask and vector length don't match. // Normalize the shuffle vector since mask and vector length don't match.
if (Src1NumElts < MaskNumElts && MaskNumElts % Src1NumElts == 0) { MVT MaskEltVT = Mask.getValueType().getVectorElementType();
// We can concat vectors to make the mask and input vector match.
if (Src1NumElts*2 == MaskNumElts && SequentialMask(Mask, 0)) { if (SrcNumElts < MaskNumElts && MaskNumElts % SrcNumElts == 0) {
// The shuffle is concatenating two vectors. // Mask is longer than the source vectors and is a multiple of the source
setValue(&I, DAG.getNode(ISD::CONCAT_VECTORS, VT, V1, V2)); // vectors. We can use concatenate vector to make the mask and vectors
// length match.
if (SrcNumElts*2 == MaskNumElts && SequentialMask(Mask, 0)) {
// The shuffle is concatenating two vectors together.
setValue(&I, DAG.getNode(ISD::CONCAT_VECTORS, VT, Srcs[0], Srcs[1]));
return; return;
} }
// Pad both vectors with undefs to the same size as the mask. // Pad both vectors with undefs to make them the same length as the mask.
unsigned NumConcat = MaskNumElts / Src1NumElts; unsigned NumConcat = MaskNumElts / SrcNumElts;
std::vector<SDValue> UnOps(Src1NumElts, SDValue UndefVal = DAG.getNode(ISD::UNDEF, SrcVT);
DAG.getNode(ISD::UNDEF,
VT1.getVectorElementType()));
SDValue UndefVal = DAG.getNode(ISD::BUILD_VECTOR, VT1,
&UnOps[0], UnOps.size());
SmallVector<SDValue, 8> MOps1, MOps2; SmallVector<SDValue, 8> MOps1, MOps2;
MOps1.push_back(V1); MOps1.push_back(Srcs[0]);
MOps2.push_back(V2); MOps2.push_back(Srcs[1]);
for (unsigned i = 1; i != NumConcat; ++i) { for (unsigned i = 1; i != NumConcat; ++i) {
MOps1.push_back(UndefVal); MOps1.push_back(UndefVal);
MOps2.push_back(UndefVal); MOps2.push_back(UndefVal);
} }
V1 = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps1[0], MOps1.size()); Srcs[0] = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps1[0], MOps1.size());
V2 = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps2[0], MOps2.size()); Srcs[1] = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps2[0], MOps2.size());
// Readjust mask for new input vector length. // Readjust mask for new input vector length.
SmallVector<SDValue, 8> MappedOps; SmallVector<SDValue, 8> MappedOps;
for (unsigned i = 0; i != MaskNumElts; ++i) { for (int i = 0; i != MaskNumElts; ++i) {
if (Mask.getOperand(i).getOpcode() == ISD::UNDEF) { if (Mask.getOperand(i).getOpcode() == ISD::UNDEF) {
MappedOps.push_back(Mask.getOperand(i)); MappedOps.push_back(Mask.getOperand(i));
} else { } else {
unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); int Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue();
if (Idx < Src1NumElts) { if (Idx < SrcNumElts)
MappedOps.push_back(DAG.getConstant(Idx, MappedOps.push_back(DAG.getConstant(Idx, MaskEltVT));
Mask.getOperand(i).getValueType())); else
} else { MappedOps.push_back(DAG.getConstant(Idx + MaskNumElts - SrcNumElts,
MappedOps.push_back(DAG.getConstant(Idx + MaskNumElts - Src1NumElts, MaskEltVT));
Mask.getOperand(i).getValueType()));
}
} }
} }
Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(), Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(),
&MappedOps[0], MappedOps.size()); &MappedOps[0], MappedOps.size());
setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, Srcs[0], Srcs[1], Mask));
return; return;
} }
if (Src1NumElts > MaskNumElts) { if (SrcNumElts > MaskNumElts) {
// Resulting vector is shorter than the incoming vector. // Resulting vector is shorter than the incoming vector.
if (Src1NumElts == MaskNumElts && SequentialMask(Mask,0)) { if (SrcNumElts == MaskNumElts && SequentialMask(Mask,0)) {
// Shuffle extracts 1st vector. // Shuffle extracts 1st vector.
setValue(&I, V1); setValue(&I, Srcs[0]);
return; return;
} }
if (Src1NumElts == MaskNumElts && SequentialMask(Mask,MaskNumElts)) { if (SrcNumElts == MaskNumElts && SequentialMask(Mask,MaskNumElts)) {
// Shuffle extracts 2nd vector. // Shuffle extracts 2nd vector.
setValue(&I, V2); setValue(&I, Srcs[1]);
return; return;
} }
// Analyze the access pattern of the vector to see if we can extract each // Analyze the access pattern of the vector to see if we can extract
// subvector and then do the shuffle. The analysis is done by calculating // two subvectors and do the shuffle. The analysis is done by calculating
// the range of elements the mask access on both vectors. If it is useful, // the range of elements the mask access on both vectors.
// we could do better by considering separate what elements are accessed int MinRange[2] = { SrcNumElts+1, SrcNumElts+1};
// in each vector (i.e., have min/max for each vector). int MaxRange[2] = {-1, -1};
int MinRange = Src1NumElts+1;
int MaxRange = -1; for (int i = 0; i != MaskNumElts; ++i) {
for (unsigned i = 0; i != MaskNumElts; ++i) {
SDValue Arg = Mask.getOperand(i); SDValue Arg = Mask.getOperand(i);
if (Arg.getOpcode() != ISD::UNDEF) { if (Arg.getOpcode() != ISD::UNDEF) {
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!"); assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
int Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); int Idx = cast<ConstantSDNode>(Arg)->getZExtValue();
if (Idx > (int) Src1NumElts) int Input = 0;
Idx -= Src1NumElts; if (Idx >= SrcNumElts) {
if (Idx > MaxRange) Input = 1;
MaxRange = Idx; Idx -= SrcNumElts;
if (Idx < MinRange) }
MinRange = Idx; if (Idx > MaxRange[Input])
MaxRange[Input] = Idx;
if (Idx < MinRange[Input])
MinRange[Input] = Idx;
} }
} }
// Adjust MinRange to start at an even boundary since this give us
// better quality splits later.
if ((unsigned) MinRange < Src1NumElts && MinRange%2 != 0)
MinRange = MinRange - 1;
if (MaxRange - MinRange < (int) MaskNumElts) {
// Extract subvector because the range is less than the new vector length
unsigned StartIdx = (MinRange/MaskNumElts)*MaskNumElts;
if (MaxRange - StartIdx < MaskNumElts) {
V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, VT, V1,
DAG.getIntPtrConstant(MinRange));
V2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, VT, V2,
DAG.getIntPtrConstant(MinRange));
// Readjust mask for new input vector length.
SmallVector<SDValue, 8> MappedOps;
for (unsigned i = 0; i != MaskNumElts; ++i) {
if (Mask.getOperand(i).getOpcode() == ISD::UNDEF) {
MappedOps.push_back(Mask.getOperand(i));
} else {
unsigned Idx =
cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue();
if (Idx < Src1NumElts) {
MappedOps.push_back(DAG.getConstant(Idx - StartIdx,
Mask.getOperand(i).getValueType()));
} else {
Idx = Idx - Src1NumElts - StartIdx + MaskNumElts;
MappedOps.push_back(DAG.getConstant(Idx,
Mask.getOperand(i).getValueType()));
}
}
}
Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(),
&MappedOps[0], MappedOps.size());
setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); // Check if the access is smaller than the vector size and can we find
return; // a reasonable extract index.
int RangeUse[2]; // 0 = Unused, 1 = Extract, 2 = Can not Extract.
int StartIdx[2]; // StartIdx to extract from
for (int Input=0; Input < 2; ++Input) {
if (MinRange[Input] == SrcNumElts+1 && MaxRange[Input] == -1) {
RangeUse[Input] = 0; // Unused
StartIdx[Input] = 0;
} else if (MaxRange[Input] - MinRange[Input] < MaskNumElts) {
// Fits within range but we should see if we can find a good
// start index that a multiple of the mask length.
if (MaxRange[Input] < MaskNumElts) {
RangeUse[Input] = 1; // Extract from beginning of the vector
StartIdx[Input] = 0;
} else {
StartIdx[Input] = (MinRange[Input]/MaskNumElts)*MaskNumElts;
if (MaxRange[Input] - StartIdx[Input] < MaskNumElts)
RangeUse[Input] = 1; // Extract from a multiple of the mask length.
else
RangeUse[Input] = 2; // Can not extract
}
} else
RangeUse[Input] = 2; // Access doesn't fit within range
}
if (RangeUse[0] == 0 && RangeUse[0] == 0) {
setValue(&I, DAG.getNode(ISD::UNDEF, VT)); // Vectors are not used.
return;
}
else if (RangeUse[0] < 2 && RangeUse[1] < 2) {
// Extract appropriate subvector and generate a vector shuffle
for (int Input=0; Input < 2; ++Input) {
if (RangeUse[Input] == 0) {
Srcs[Input] = DAG.getNode(ISD::UNDEF, VT);
} else {
Srcs[Input] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, VT, Srcs[Input],
DAG.getIntPtrConstant(StartIdx[Input]));
}
} }
// Calculate new mask.
SmallVector<SDValue, 8> MappedOps;
for (int i = 0; i != MaskNumElts; ++i) {
SDValue Arg = Mask.getOperand(i);
if (Arg.getOpcode() == ISD::UNDEF) {
MappedOps.push_back(Arg);
} else {
int Idx = cast<ConstantSDNode>(Arg)->getZExtValue();
if (Idx < SrcNumElts)
MappedOps.push_back(DAG.getConstant(Idx - StartIdx[0], MaskEltVT));
else {
Idx = Idx - SrcNumElts - StartIdx[1] + MaskNumElts;
MappedOps.push_back(DAG.getConstant(Idx, MaskEltVT));
}
}
}
Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(),
&MappedOps[0], MappedOps.size());
setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, Srcs[0], Srcs[1], Mask));
return;
} }
} }
// We can't use either concat vectors or extract subvectors so we fall back // We can't use either concat vectors or extract subvectors so fall back to
// to insert and extracts. // replacing the shuffle with extract and build vector.
// to insert and build vector.
MVT EltVT = VT.getVectorElementType(); MVT EltVT = VT.getVectorElementType();
MVT PtrVT = TLI.getPointerTy(); MVT PtrVT = TLI.getPointerTy();
SmallVector<SDValue,8> Ops; SmallVector<SDValue,8> Ops;
for (unsigned i = 0; i != MaskNumElts; ++i) { for (int i = 0; i != MaskNumElts; ++i) {
SDValue Arg = Mask.getOperand(i); SDValue Arg = Mask.getOperand(i);
if (Arg.getOpcode() == ISD::UNDEF) { if (Arg.getOpcode() == ISD::UNDEF) {
Ops.push_back(DAG.getNode(ISD::UNDEF, EltVT)); Ops.push_back(DAG.getNode(ISD::UNDEF, EltVT));
} else { } else {
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!"); assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
unsigned Idx = cast<ConstantSDNode>(Arg)->getZExtValue(); int Idx = cast<ConstantSDNode>(Arg)->getZExtValue();
if (Idx < Src1NumElts) if (Idx < SrcNumElts)
Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, V1, Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, Srcs[0],
DAG.getConstant(Idx, PtrVT))); DAG.getConstant(Idx, PtrVT)));
else else
Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, V2, Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, Srcs[1],
DAG.getConstant(Idx - Src1NumElts, PtrVT))); DAG.getConstant(Idx - SrcNumElts, PtrVT)));
} }
} }
setValue(&I, DAG.getNode(ISD::BUILD_VECTOR, VT, &Ops[0], Ops.size())); setValue(&I, DAG.getNode(ISD::BUILD_VECTOR, VT, &Ops[0], Ops.size()));

View File

@ -0,0 +1,34 @@
; RUN: llvm-as < %s | llc -march=x86 -mattr=sse41 -o %t -f
; RUN: grep unpcklps %t | count 3
; RUN: grep unpckhps %t | count 1
; Transpose example using the more generic vector shuffle. We return
; float8 instead of float16 since x86 can return that in register.
; ModuleID = 'transpose2_opt.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-apple-cl.1.0"
@r0 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r1 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r2 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r3 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
define <8 x float> @__transpose2(<4 x float> %p0, <4 x float> %p1, <4 x float> %p2, <4 x float> %p3) nounwind {
entry:
%unpcklps = shufflevector <4 x float> %p0, <4 x float> %p2, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=2]
%unpckhps = shufflevector <4 x float> %p0, <4 x float> %p2, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=2]
%unpcklps8 = shufflevector <4 x float> %p1, <4 x float> %p3, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=2]
%unpckhps11 = shufflevector <4 x float> %p1, <4 x float> %p3, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=2]
%unpcklps14 = shufflevector <4 x float> %unpcklps, <4 x float> %unpcklps8, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=1]
%unpcklps14a = shufflevector <4 x float> %unpcklps14, <4 x float> undef, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>;
%unpckhps17 = shufflevector <4 x float> %unpcklps, <4 x float> %unpcklps8, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=1]
%unpckhps17a = shufflevector <4 x float> %unpckhps17, <4 x float> undef, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>;
%r1 = shufflevector <16 x float> %unpcklps14a, <16 x float> %unpckhps17a, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 16, i32 17, i32 18, i32 19, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>;
%unpcklps20 = shufflevector <4 x float> %unpckhps, <4 x float> %unpckhps11, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=1]
%unpcklps20a = shufflevector <4 x float> %unpcklps20, <4 x float> undef, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>;
%r2 = shufflevector <16 x float> %r1, <16 x float> %unpcklps20a, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 16, i32 17, i32 18, i32 19, i32 12, i32 13, i32 14, i32 15>;
%unpckhps23 = shufflevector <4 x float> %unpckhps, <4 x float> %unpckhps11, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=1]
%unpckhps23a = shufflevector <4 x float> %unpckhps23, <4 x float> undef, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>;
%r3 = shufflevector <16 x float> %r2, <16 x float> %unpckhps23a, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 16, i32 17, i32 18, i32 19>;
%r4 = shufflevector <16 x float> %r3, <16 x float> undef, <8 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>;
ret <8 x float> %r4;
}

View File

@ -0,0 +1,29 @@
; RUN: llvm-as < %s | llc -march=x86 -mattr=sse41 -o %t -f
; RUN: grep unpcklps %t | count 1
; RUN: grep unpckhps %t | count 3
; Transpose example using the more generic vector shuffle. Return float8
; instead of float16
; ModuleID = 'transpose2_opt.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i386-apple-cl.1.0"
@r0 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r1 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r2 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
@r3 = common global <4 x float> zeroinitializer, align 16 ; <<4 x float>*> [#uses=1]
define <8 x float> @__transpose2(<4 x float> %p0, <4 x float> %p1, <4 x float> %p2, <4 x float> %p3) nounwind {
entry:
%unpcklps = shufflevector <4 x float> %p0, <4 x float> %p2, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=2]
%unpckhps = shufflevector <4 x float> %p0, <4 x float> %p2, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=2]
%unpcklps8 = shufflevector <4 x float> %p1, <4 x float> %p3, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=2]
%unpckhps11 = shufflevector <4 x float> %p1, <4 x float> %p3, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=2]
%unpcklps14 = shufflevector <4 x float> %unpcklps, <4 x float> %unpcklps8, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=1]
%unpckhps17 = shufflevector <4 x float> %unpcklps, <4 x float> %unpcklps8, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=1]
%r1 = shufflevector <4 x float> %unpcklps14, <4 x float> %unpckhps17, <8 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7 >;
%unpcklps20 = shufflevector <4 x float> %unpckhps, <4 x float> %unpckhps11, <4 x i32> < i32 0, i32 4, i32 1, i32 5 > ; <<4 x float>> [#uses=1]
%unpckhps23 = shufflevector <4 x float> %unpckhps, <4 x float> %unpckhps11, <4 x i32> < i32 2, i32 6, i32 3, i32 7 > ; <<4 x float>> [#uses=1]
%r2 = shufflevector <4 x float> %unpcklps20, <4 x float> %unpckhps23, <8 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7 >;
; %r3 = shufflevector <8 x float> %r1, <8 x float> %r2, <16 x i32> < i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15 >;
ret <8 x float> %r2;
}

View File

@ -0,0 +1,17 @@
; RUN: llvm-as < %s | llc -march=x86 -mattr=sse41 -o %t -f
; RUN: grep addps %t | count 2
; RUN: grep mulps %t | count 2
; RUN: grep subps %t | count 2
; ModuleID = 'vec_shuffle-27.bc'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i686-apple-cl.1.0"
define <8 x float> @my2filter4_1d(<4 x float> %a, <8 x float> %T0, <8 x float> %T1) nounwind readnone {
entry:
%tmp7 = shufflevector <4 x float> %a, <4 x float> undef, <8 x i32> < i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3 > ; <<8 x float>> [#uses=1]
%sub = sub <8 x float> %T1, %T0 ; <<8 x float>> [#uses=1]
%mul = mul <8 x float> %sub, %tmp7 ; <<8 x float>> [#uses=1]
%add = add <8 x float> %mul, %T0 ; <<8 x float>> [#uses=1]
ret <8 x float> %add
}