diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4082,8 +4082,6 @@ const SimplifyQuery &Q, bool AllowRefinement, unsigned MaxRecurse) { - assert(!Op->getType()->isVectorTy() && "This is not safe for vectors"); - // Trivial replacement. if (V == Op) return RepOp; @@ -4096,6 +4094,14 @@ if (!I || !is_contained(I->operands(), Op)) return nullptr; + if (Op->getType()->isVectorTy()) { + // For vector types, the simplification must hold per-lane, so forbid + // potentially cross-lane operations like shufflevector. + assert(I->getType()->isVectorTy() && "Vector type mismatch"); + if (isa(I) || isa(I)) + return nullptr; + } + // Replace Op with RepOp in instruction operands. SmallVector NewOps(I->getNumOperands()); transform(I->operands(), NewOps.begin(), @@ -4325,9 +4331,7 @@ // If we have a scalar equality comparison, then we know the value in one of // the arms of the select. See if substituting this value into the arm and // simplifying the result yields the same value as the other arm. - // Note that the equivalence/replacement opportunity does not hold for vectors - // because each element of a vector select is chosen independently. - if (Pred == ICmpInst::ICMP_EQ && !CondVal->getType()->isVectorTy()) { + if (Pred == ICmpInst::ICMP_EQ) { if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, /* AllowRefinement */ false, MaxRecurse) == TrueVal || diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1164,10 +1164,7 @@ /// TODO: Wrapping flags could be preserved in some cases with better analysis. Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp) { - // Value equivalence substitution requires an all-or-nothing replacement. - // It does not make sense for a vector compare where each lane is chosen - // independently. - if (!Cmp.isEquality() || Cmp.getType()->isVectorTy()) + if (!Cmp.isEquality()) return nullptr; // Canonicalize the pattern to ICMP_EQ by swapping the select operands. @@ -1197,7 +1194,9 @@ // undefined behavior). Only do this if CmpRHS is a constant, as // profitability is not clear for other cases. // FIXME: The replacement could be performed recursively. - if (match(CmpRHS, m_ImmConstant()) && !match(CmpLHS, m_ImmConstant())) + // FIXME: Support vectors. + if (match(CmpRHS, m_ImmConstant()) && !match(CmpLHS, m_ImmConstant()) && + !Cmp.getType()->isVectorTy()) if (auto *I = dyn_cast(TrueVal)) if (I->hasOneUse() && isSafeToSpeculativelyExecute(I)) for (Use &U : I->operands()) @@ -2795,14 +2794,12 @@ return BinaryOperator::CreateAnd(FalseVal, Builder.CreateOr(C, TrueVal)); } - if (!SelType->isVectorTy()) { - if (Value *S = simplifyWithOpReplaced(TrueVal, CondVal, One, SQ, - /* AllowRefinement */ true)) - return replaceOperand(SI, 1, S); - if (Value *S = simplifyWithOpReplaced(FalseVal, CondVal, Zero, SQ, - /* AllowRefinement */ true)) - return replaceOperand(SI, 2, S); - } + if (Value *S = simplifyWithOpReplaced(TrueVal, CondVal, One, SQ, + /* AllowRefinement */ true)) + return replaceOperand(SI, 1, S); + if (Value *S = simplifyWithOpReplaced(FalseVal, CondVal, Zero, SQ, + /* AllowRefinement */ true)) + return replaceOperand(SI, 2, S); if (match(FalseVal, m_Zero()) || match(TrueVal, m_One())) { Use *Y = nullptr; diff --git a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll --- a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll +++ b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll @@ -308,9 +308,7 @@ } define <2 x i1> @land_lor_right2_vec(<2 x i1> %A, <2 x i1> %B) { ; CHECK-LABEL: @land_lor_right2_vec( -; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[A:%.*]], <2 x i1> zeroinitializer -; CHECK-NEXT: [[RES:%.*]] = select <2 x i1> [[A]], <2 x i1> , <2 x i1> [[C]] -; CHECK-NEXT: ret <2 x i1> [[RES]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %c = select <2 x i1> %B, <2 x i1> %A, <2 x i1> zeroinitializer %res = select <2 x i1> %A, <2 x i1> , <2 x i1> %c diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -1460,10 +1460,8 @@ define <2 x i32> @PR27817_nsw_vec(<2 x i32> %x) { ; CHECK-LABEL: @PR27817_nsw_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[SUB:%.*]] = sub nsw <2 x i32> zeroinitializer, [[X]] -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> , <2 x i32> [[SUB]] -; CHECK-NEXT: ret <2 x i32> [[SEL]] +; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] +; CHECK-NEXT: ret <2 x i32> [[SUB]] ; %cmp = icmp eq <2 x i32> %x, %sub = sub nsw <2 x i32> zeroinitializer, %x @@ -2785,8 +2783,7 @@ define <2 x i8> @select_replacement_add_eq_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @select_replacement_add_eq_vec( ; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> [[Y:%.*]] +; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> , <2 x i8> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i8> [[SEL]] ; %cmp = icmp eq <2 x i8> %x, @@ -2798,8 +2795,7 @@ define <2 x i8> @select_replacement_add_eq_vec_nonuniform(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @select_replacement_add_eq_vec_nonuniform( ; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> [[Y:%.*]] +; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> , <2 x i8> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i8> [[SEL]] ; %cmp = icmp eq <2 x i8> %x, diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll --- a/llvm/test/Transforms/InstSimplify/select.ll +++ b/llvm/test/Transforms/InstSimplify/select.ll @@ -988,10 +988,8 @@ define <2 x i32> @select_neutral_add_rhs_vec(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @select_neutral_add_rhs_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[Y:%.*]], zeroinitializer -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[X:%.*]], [[Y]] -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[ADD]], <2 x i32> [[X]] -; CHECK-NEXT: ret <2 x i32> [[SEL]] +; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret <2 x i32> [[ADD]] ; %cmp = icmp ne <2 x i32> %y, zeroinitializer %add = add <2 x i32> %x, %y @@ -1001,10 +999,8 @@ define <2 x i32> @select_neutral_add_lhs_vec(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @select_neutral_add_lhs_vec( -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[Y:%.*]], zeroinitializer -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[Y]], [[X:%.*]] -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[ADD]], <2 x i32> [[X]] -; CHECK-NEXT: ret <2 x i32> [[SEL]] +; CHECK-NEXT: [[ADD:%.*]] = add <2 x i32> [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: ret <2 x i32> [[ADD]] ; %cmp = icmp ne <2 x i32> %y, zeroinitializer %add = add <2 x i32> %y, %x @@ -1047,6 +1043,7 @@ ret i32 %sel } +; FIXME: This is safe to fold. define <2 x i32> @select_ctpop_zero_vec(<2 x i32> %x) { ; CHECK-LABEL: @select_ctpop_zero_vec( ; CHECK-NEXT: [[T0:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer @@ -1060,6 +1057,7 @@ ret <2 x i32> %sel } +; Negative test: Cannot fold due to cross-lane intrinsic. define <2 x i32> @select_vector_reverse(<2 x i32> %x) { ; CHECK-LABEL: @select_vector_reverse( ; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer