From: Sanjay Patel Date: Mon, 8 Jul 2019 16:26:48 +0000 (+0000) Subject: [InstCombine] canonicalize insert+splat to/from element 0 of vector X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ea3ab8c4b7cfd025f0748dc980572dbf1886bd6e;p=llvm [InstCombine] canonicalize insert+splat to/from element 0 of vector We recognize a splat from element 0 in (VectorUtils) llvm::getSplatValue() and also in ShuffleVectorInst::isZeroEltSplatMask(), so this converts to that form for better matching. The backend generically turns these patterns into build_vector, so there should be no codegen difference. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365342 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index 22d1e48cd96..b928ae5b3d1 100644 --- a/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -1346,6 +1346,41 @@ static Instruction *foldSelectShuffleWith1Binop(ShuffleVectorInst &Shuf) { return NewBO; } +/// If we have an insert of a scalar to a non-zero element of an undefined +/// vector and then shuffle that value, that's the same as inserting to the zero +/// element and shuffling. Splatting from the zero element is recognized as the +/// canonical form of splat. +static Instruction *canonicalizeInsertSplat(ShuffleVectorInst &Shuf, + InstCombiner::BuilderTy &Builder) { + Value *Op0 = Shuf.getOperand(0), *Op1 = Shuf.getOperand(1); + Constant *Mask = Shuf.getMask(); + Value *X; + uint64_t IndexC; + + // Match a shuffle that is a splat to a non-zero element. + if (!match(Op0, m_OneUse(m_InsertElement(m_Undef(), m_Value(X), + m_ConstantInt(IndexC)))) || + !match(Op1, m_Undef()) || match(Mask, m_ZeroInt()) || IndexC == 0) + return nullptr; + + // Insert into element 0 of an undef vector. + UndefValue *UndefVec = UndefValue::get(Shuf.getType()); + Constant *Zero = Builder.getInt32(0); + Value *NewIns = Builder.CreateInsertElement(UndefVec, X, Zero); + + // Splat from element 0. Any mask element that is undefined remains undefined. + // For example: + // shuf (inselt undef, X, 2), undef, <2,2,undef> + // --> shuf (inselt undef, X, 0), undef, <0,0,undef> + unsigned NumMaskElts = Shuf.getType()->getVectorNumElements(); + SmallVector NewMask(NumMaskElts, Zero); + for (unsigned i = 0; i != NumMaskElts; ++i) + if (isa(Mask->getAggregateElement(i))) + NewMask[i] = Mask->getAggregateElement(i); + + return new ShuffleVectorInst(NewIns, UndefVec, ConstantVector::get(NewMask)); +} + /// Try to fold shuffles that are the equivalent of a vector select. static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf, InstCombiner::BuilderTy &Builder, @@ -1714,6 +1749,9 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { return &SVI; } + if (Instruction *I = canonicalizeInsertSplat(SVI, Builder)) + return I; + if (Instruction *I = foldSelectShuffle(SVI, Builder, DL)) return I; diff --git a/test/Transforms/InstCombine/insert-extract-shuffle.ll b/test/Transforms/InstCombine/insert-extract-shuffle.ll index f3cb6ff9fae..a1f7fca80c3 100644 --- a/test/Transforms/InstCombine/insert-extract-shuffle.ll +++ b/test/Transforms/InstCombine/insert-extract-shuffle.ll @@ -427,8 +427,8 @@ define <5 x float> @insert_not_undef_shuffle_translate_commute_lengthen(float %x define <4 x float> @insert_nonzero_index_splat(float %x) { ; CHECK-LABEL: @insert_nonzero_index_splat( -; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x float> undef, float [[X:%.*]], i32 2 -; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[XV]], <4 x float> undef, <4 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = insertelement <4 x float> undef, float [[X:%.*]], i32 0 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[TMP1]], <4 x float> undef, <4 x i32> ; CHECK-NEXT: ret <4 x float> [[SPLAT]] ; %xv = insertelement <4 x float> undef, float %x, i32 2 @@ -438,8 +438,8 @@ define <4 x float> @insert_nonzero_index_splat(float %x) { define <3 x double> @insert_nonzero_index_splat_narrow(double %x) { ; CHECK-LABEL: @insert_nonzero_index_splat_narrow( -; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x double> undef, double [[X:%.*]], i32 3 -; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x double> [[XV]], <4 x double> undef, <3 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = insertelement <3 x double> undef, double [[X:%.*]], i32 0 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x double> [[TMP1]], <3 x double> undef, <3 x i32> ; CHECK-NEXT: ret <3 x double> [[SPLAT]] ; %xv = insertelement <4 x double> undef, double %x, i32 3 @@ -449,8 +449,8 @@ define <3 x double> @insert_nonzero_index_splat_narrow(double %x) { define <5 x i7> @insert_nonzero_index_splat_widen(i7 %x) { ; CHECK-LABEL: @insert_nonzero_index_splat_widen( -; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x i7> undef, i7 [[X:%.*]], i32 1 -; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i7> [[XV]], <4 x i7> undef, <5 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = insertelement <5 x i7> undef, i7 [[X:%.*]], i32 0 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <5 x i7> [[TMP1]], <5 x i7> undef, <5 x i32> ; CHECK-NEXT: ret <5 x i7> [[SPLAT]] ; %xv = insertelement <4 x i7> undef, i7 %x, i32 1 @@ -458,6 +458,8 @@ define <5 x i7> @insert_nonzero_index_splat_widen(i7 %x) { ret <5 x i7> %splat } +; Negative test - don't increase instruction count + define <4 x float> @insert_nonzero_index_splat_extra_use(float %x) { ; CHECK-LABEL: @insert_nonzero_index_splat_extra_use( ; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x float> undef, float [[X:%.*]], i32 2 @@ -470,3 +472,29 @@ define <4 x float> @insert_nonzero_index_splat_extra_use(float %x) { %splat = shufflevector <4 x float> %xv, <4 x float> undef, <4 x i32> ret <4 x float> %splat } + +; Negative test - non-undef base vector + +define <4 x float> @insert_nonzero_index_splat_wrong_base(float %x, <4 x float> %y) { +; CHECK-LABEL: @insert_nonzero_index_splat_wrong_base( +; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x float> [[Y:%.*]], float [[X:%.*]], i32 2 +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[XV]], <4 x float> undef, <4 x i32> +; CHECK-NEXT: ret <4 x float> [[SPLAT]] +; + %xv = insertelement <4 x float> %y, float %x, i32 2 + %splat = shufflevector <4 x float> %xv, <4 x float> undef, <4 x i32> + ret <4 x float> %splat +} + +; Negative test - non-constant insert index + +define <4 x float> @insert_nonzero_index_splat_wrong_index(float %x, i32 %index) { +; CHECK-LABEL: @insert_nonzero_index_splat_wrong_index( +; CHECK-NEXT: [[XV:%.*]] = insertelement <4 x float> undef, float [[X:%.*]], i32 [[INDEX:%.*]] +; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[XV]], <4 x float> undef, <4 x i32> +; CHECK-NEXT: ret <4 x float> [[SPLAT]] +; + %xv = insertelement <4 x float> undef, float %x, i32 %index + %splat = shufflevector <4 x float> %xv, <4 x float> undef, <4 x i32> + ret <4 x float> %splat +}