From 973ff7c74c6eb1073376834ce27588caeebfb034 Mon Sep 17 00:00:00 2001 From: Zvi Rackover Date: Sun, 7 May 2017 18:16:37 +0000 Subject: [PATCH] InstructionSimplify: Relanding r301766 Summary: Re-applying r301766 with a fix to a typo and a regression test. The log message for r301766 was: ================================================================================== InstructionSimplify: Canonicalize shuffle operands. NFC-ish. Summary: Apply canonicalization rules: 1. Input vectors with no elements selected from can be replaced with undef. 2. If only one input vector is constant it shall be the second one. This allows constant-folding to cover more ad-hoc simplifications that were in place and avoid duplication for RHS and LHS checks. There are more rules we may want to add in the future when we see a justification. e.g. mask elements that select undef elements can be replaced with undef. ================================================================================== Reviewers: spatel, RKSimon Reviewed By: spatel Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32863 llvm-svn: 302373 --- llvm/lib/Analysis/InstructionSimplify.cpp | 51 +++++++++++-------- .../Transforms/InstSimplify/shufflevector.ll | 14 +++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 18ac3696399b4..4a713f441ce87 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4094,20 +4094,13 @@ static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask, unsigned MaskNumElts = Mask->getType()->getVectorNumElements(); unsigned InVecNumElts = InVecTy->getVectorNumElements(); - auto *Op0Const = dyn_cast(Op0); - auto *Op1Const = dyn_cast(Op1); - - // If all operands are constant, constant fold the shuffle. - if (Op0Const && Op1Const) - return ConstantFoldShuffleVectorInstruction(Op0Const, Op1Const, Mask); - SmallVector Indices; ShuffleVectorInst::getShuffleMask(Mask, Indices); assert(MaskNumElts == Indices.size() && "Size of Indices not same as number of mask elements?"); - // If only one of the operands is constant, constant fold the shuffle if the - // mask does not select elements from the variable operand. + // Canonicalization: If mask does not select elements from an input vector, + // replace that input vector with undef. bool MaskSelects0 = false, MaskSelects1 = false; for (unsigned i = 0; i != MaskNumElts; ++i) { if (Indices[i] == -1) @@ -4117,23 +4110,41 @@ static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask, else MaskSelects1 = true; } - if (!MaskSelects0 && Op1Const) - return ConstantFoldShuffleVectorInstruction(UndefValue::get(InVecTy), - Op1Const, Mask); - if (!MaskSelects1 && Op0Const) - return ConstantFoldShuffleVectorInstruction(Op0Const, - UndefValue::get(InVecTy), Mask); + if (!MaskSelects0) + Op0 = UndefValue::get(InVecTy); + if (!MaskSelects1) + Op1 = UndefValue::get(InVecTy); + + auto *Op0Const = dyn_cast(Op0); + auto *Op1Const = dyn_cast(Op1); + + // If all operands are constant, constant fold the shuffle. + if (Op0Const && Op1Const) + return ConstantFoldShuffleVectorInstruction(Op0Const, Op1Const, Mask); + + // Canonicalization: if only one input vector is constant, it shall be the + // second one. + if (Op0Const && !Op1Const) { + std::swap(Op0, Op1); + for (int &Idx : Indices) { + if (Idx == -1) + continue; + Idx = Idx < (int)InVecNumElts ? Idx + InVecNumElts : Idx - InVecNumElts; + assert(Idx >= 0 && Idx < (int)InVecNumElts * 2 && + "shufflevector mask index out of range"); + } + Mask = ConstantDataVector::get( + Mask->getContext(), + makeArrayRef(reinterpret_cast(Indices.data()), + MaskNumElts)); + } // A shuffle of a splat is always the splat itself. Legal if the shuffle's // value type is same as the input vectors' type. if (auto *OpShuf = dyn_cast(Op0)) - if (!MaskSelects1 && RetTy == InVecTy && + if (isa(Op1) && RetTy == InVecTy && OpShuf->getMask()->getSplatValue()) return Op0; - if (auto *OpShuf = dyn_cast(Op1)) - if (!MaskSelects0 && RetTy == InVecTy && - OpShuf->getMask()->getSplatValue()) - return Op1; // Don't fold a shuffle with undef mask elements. This may get folded in a // better way using demanded bits or other analysis. diff --git a/llvm/test/Transforms/InstSimplify/shufflevector.ll b/llvm/test/Transforms/InstSimplify/shufflevector.ll index 6af0db8e5a442..cc49ae3554c05 100644 --- a/llvm/test/Transforms/InstSimplify/shufflevector.ll +++ b/llvm/test/Transforms/InstSimplify/shufflevector.ll @@ -233,3 +233,17 @@ define <8 x i64> @PR30630(<8 x i64> %x) { ret <8 x i64> %s7 } +; This case covers internal canonicalization of shuffles with one constant input vector. + +;FIXME: Another issue exposed here, this whole function could be simplified to: +; ret <2 x float> zeroinitializer +define <2 x float> @PR32872(<2 x float> %x) { +; CHECK-LABEL: @PR32872( +; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> zeroinitializer, <4 x i32> +; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <4 x float> zeroinitializer, <4 x float> [[TMP1]], <2 x i32> +; CHECK-NEXT: ret <2 x float> [[TMP4]] +; + %tmp1 = shufflevector <2 x float> %x, <2 x float> zeroinitializer, <4 x i32> + %tmp4 = shufflevector <4 x float> zeroinitializer, <4 x float> %tmp1, <2 x i32> + ret <2 x float> %tmp4 +}