Index: llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -18,6 +18,7 @@ #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/KnownBits.h" +#include using namespace llvm; using namespace llvm::PatternMatch; @@ -1502,13 +1503,61 @@ // If this is a vector select, try to transform the select condition based // on the current demanded elements. SelectInst *Sel = cast(I); - if (Sel->getCondition()->getType()->isVectorTy()) { + if (isa(Sel->getCondition()->getType())) { + // Peek through shuffled true/false operands of the select. + // If an operand is not shuffled, simulate with an identity shuffle. + Value *LHS = Sel->getTrueValue(), *RHS = Sel->getFalseValue(); + ArrayRef TMask, FMask; + SmallVector IdentityMask(VWidth); + std::iota(IdentityMask.begin(), IdentityMask.end(), 0); + Value *T0, *T1; + if (!match(LHS, m_Shuffle(m_Value(T0), m_Value(T1), m_Mask(TMask)))) { + TMask = IdentityMask; + T0 = LHS; + T1 = nullptr; + } + Value *F0, *F1; + if (!match(RHS, m_Shuffle(m_Value(F0), m_Value(F1), m_Mask(FMask)))) { + FMask = IdentityMask; + F0 = RHS; + F1 = nullptr; + } + + // If an element is the same in the true/false operands, the corresponding + // element of the select condition is unnecessary. + APInt DemandedCond(DemandedElts); + int NumElts = VWidth; + for (int i = 0; i < NumElts; ++i) { + // If both operands are undefined at this element, the condition element + // does not matter. Poison can't propagate through this element of the + // select. + if (TMask[i] == UndefMaskElem && FMask[i] == UndefMaskElem) { + DemandedCond.clearBit(i); + continue; + } + + // If only one operand is undefined in the element, we can't change + // the condition because the select may block or propagate poison. + if (TMask[i] == UndefMaskElem || FMask[i] == UndefMaskElem) + continue; + + assert(TMask[i] >= 0 && FMask[i] >= 0 && TMask[i] < NumElts * 2 && + FMask[i] < NumElts * 2 && "Unexpected shuffle mask"); + Value *TSrc = TMask[i] < NumElts ? T0 : T1; + Value *FSrc = FMask[i] < NumElts ? F0 : F1; + + // Are these the same element of the same vector? + assert(TSrc && FSrc && "Unexpected shuffle operand"); + if (TSrc == FSrc && (TMask[i] % NumElts) == (FMask[i] % NumElts)) + DemandedCond.clearBit(i); + } + // TODO: We are not doing anything with UndefElts based on this call. // It is overwritten below based on the other select operands. If an // element of the select condition is known undef, then we are free to // choose the output value from either arm of the select. If we know that // one of those values is undef, then the output can be undef. - simplifyAndSetOp(I, 0, DemandedElts, UndefElts); + simplifyAndSetOp(I, 0, DemandedCond, UndefElts); } // Next, see if we can transform the arms of the select. Index: llvm/test/Transforms/InstCombine/vec_demanded_elts.ll =================================================================== --- llvm/test/Transforms/InstCombine/vec_demanded_elts.ll +++ llvm/test/Transforms/InstCombine/vec_demanded_elts.ll @@ -678,8 +678,7 @@ define <4 x i8> @select_cond_with_eq_true_false_elts(<4 x i8> %x, <4 x i8> %y, <4 x i1> %cmp) { ; CHECK-LABEL: @select_cond_with_eq_true_false_elts( ; CHECK-NEXT: [[TVAL:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]], <4 x i32> -; CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x i1> [[CMP:%.*]], <4 x i1> undef, <4 x i32> zeroinitializer -; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[SPLAT]], <4 x i8> [[TVAL]], <4 x i8> [[Y]] +; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i8> [[TVAL]], <4 x i8> [[Y]] ; CHECK-NEXT: ret <4 x i8> [[R]] ; %tval = shufflevector <4 x i8> %x, <4 x i8> %y, <4 x i32> @@ -693,7 +692,7 @@ define <4 x i8> @select_cond_with_eq_true_false_elts2(<4 x i8> %x, <4 x i8> %y, <4 x i1> %cmp) { ; CHECK-LABEL: @select_cond_with_eq_true_false_elts2( ; CHECK-NEXT: [[TVAL:%.*]] = shufflevector <4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]], <4 x i32> -; CHECK-NEXT: [[COND:%.*]] = shufflevector <4 x i1> [[CMP:%.*]], <4 x i1> undef, <4 x i32> +; CHECK-NEXT: [[COND:%.*]] = shufflevector <4 x i1> [[CMP:%.*]], <4 x i1> undef, <4 x i32> ; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[COND]], <4 x i8> [[TVAL]], <4 x i8> [[X]] ; CHECK-NEXT: ret <4 x i8> [[R]] ; @@ -710,7 +709,7 @@ ; CHECK-LABEL: @select_cond_with_eq_true_false_elts3( ; CHECK-NEXT: [[TVAL:%.*]] = shufflevector <4 x float> [[X:%.*]], <4 x float> [[Y:%.*]], <4 x i32> ; CHECK-NEXT: [[FVAL:%.*]] = shufflevector <4 x float> [[Y]], <4 x float> [[X]], <4 x i32> -; CHECK-NEXT: [[COND:%.*]] = shufflevector <4 x i1> [[CMP:%.*]], <4 x i1> undef, <4 x i32> +; CHECK-NEXT: [[COND:%.*]] = shufflevector <4 x i1> [[CMP:%.*]], <4 x i1> undef, <4 x i32> ; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[COND]], <4 x float> [[TVAL]], <4 x float> [[FVAL]] ; CHECK-NEXT: ret <4 x float> [[R]] ; @@ -721,6 +720,8 @@ ret <4 x float> %r } +; Negative test - only 1 side of the select is undef at element 0; can't change the condition. + define <4 x i8> @select_cond_with_undef_true_false_elts(<4 x i8> %x, <4 x i8> %y, <4 x i1> %cmp) { ; CHECK-LABEL: @select_cond_with_undef_true_false_elts( ; CHECK-NEXT: [[TVAL:%.*]] = shufflevector <4 x i8> [[Y:%.*]], <4 x i8> undef, <4 x i32>