Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -65,6 +65,43 @@ static Value *SimplifyGEPInst(Type *, ArrayRef, const SimplifyQuery &, unsigned); +/// Folds +/// %A = icmp ne i8 %X, %V1 +/// %B = icmp ne i8 %X, %V2 +/// %C = or i1 %A, %B +/// %D = select i1 %C, i8 %X, i8 %V1 +/// ret i8 %D +/// => +/// ret i8 %X +/// +/// Also folds AND variant +static Value *foldSelectWithBinaryOp(Value *Cond, Value *TrueVal, + Value *FalseVal) { + BinaryOperator::BinaryOps BinOpCode; + if (auto *BO = dyn_cast(Cond)) + BinOpCode = BO->getOpcode(); + else + return nullptr; + + CmpInst::Predicate ExpectedPred; + if (BinOpCode == BinaryOperator::Or) { + ExpectedPred = ICmpInst::ICMP_NE; + } else if (BinOpCode == BinaryOperator::And) { + ExpectedPred = ICmpInst::ICMP_EQ; + } else + return nullptr; + + CmpInst::Predicate Pred1, Pred2; + if (!match( + Cond, + m_c_BinOp(m_c_ICmp(Pred1, m_Specific(TrueVal), m_Specific(FalseVal)), + m_c_ICmp(Pred2, m_Specific(TrueVal), m_Value()))) || + Pred1 != Pred2 || Pred1 != ExpectedPred) + return nullptr; + + return BinOpCode == BinaryOperator::Or ? TrueVal : FalseVal; +} + /// For a boolean type or a vector of boolean type, return false or a vector /// with every element false. static Constant *getFalse(Type *Ty) { @@ -3752,6 +3789,9 @@ simplifySelectWithICmpCond(Cond, TrueVal, FalseVal, Q, MaxRecurse)) return V; + if (Value *V = foldSelectWithBinaryOp(Cond, TrueVal, FalseVal)) + return V; + return nullptr; } Index: test/Transforms/InstCombine/select-and-cmp.ll =================================================================== --- test/Transforms/InstCombine/select-and-cmp.ll +++ test/Transforms/InstCombine/select-and-cmp.ll @@ -5,11 +5,7 @@ define i32 @select_and_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_and_icmp( -; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[X:%.*]] ; %A = icmp eq i32 %x, %z %B = icmp eq i32 %y, %z @@ -20,11 +16,7 @@ define <2 x i8> @select_and_icmp_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_and_icmp_vec( -; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp eq <2 x i8> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = and <2 x i1> [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[C]], <2 x i8> [[Z]], <2 x i8> [[X]] -; CHECK-NEXT: ret <2 x i8> [[D]] +; CHECK-NEXT: ret <2 x i8> [[X:%.*]] ; %A = icmp eq <2 x i8> %x, %z %B = icmp eq <2 x i8> %y, %z @@ -35,11 +27,7 @@ define i32 @select_and_icmp2(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_and_icmp2( -; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[Y]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[Y:%.*]] ; %A = icmp eq i32 %x, %z %B = icmp eq i32 %y, %z @@ -50,11 +38,7 @@ define i32 @select_and_inv_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_and_inv_icmp( -; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = and i1 [[B]], [[A]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[X:%.*]] ; %A = icmp eq i32 %x, %z %B = icmp eq i32 %y, %z @@ -65,11 +49,7 @@ define i32 @select_and_icmp_inv(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_and_icmp_inv( -; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = and i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[X:%.*]] ; %A = icmp eq i32 %z, %x %B = icmp eq i32 %z, %y Index: test/Transforms/InstCombine/select-or-cmp.ll =================================================================== --- test/Transforms/InstCombine/select-or-cmp.ll +++ test/Transforms/InstCombine/select-or-cmp.ll @@ -5,11 +5,7 @@ define i32 @select_or_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_or_icmp( -; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[Z:%.*]] ; %A = icmp ne i32 %x, %z %B = icmp ne i32 %y, %z @@ -20,11 +16,7 @@ define <2 x i8> @select_or_icmp_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_or_icmp_vec( -; CHECK-NEXT: [[A:%.*]] = icmp ne <2 x i8> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp ne <2 x i8> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = or <2 x i1> [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select <2 x i1> [[C]], <2 x i8> [[Z]], <2 x i8> [[X]] -; CHECK-NEXT: ret <2 x i8> [[D]] +; CHECK-NEXT: ret <2 x i8> [[Z:%.*]] ; %A = icmp ne <2 x i8> %x, %z %B = icmp ne <2 x i8> %y, %z @@ -35,11 +27,7 @@ define i32 @select_or_icmp2(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_or_icmp2( -; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[Y]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[Z:%.*]] ; %A = icmp ne i32 %x, %z %B = icmp ne i32 %y, %z @@ -50,11 +38,7 @@ define i32 @select_or_inv_icmp(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_or_inv_icmp( -; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[C:%.*]] = or i1 [[B]], [[A]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[Z:%.*]] ; %A = icmp ne i32 %x, %z %B = icmp ne i32 %y, %z @@ -65,11 +49,7 @@ define i32 @select_or_icmp_inv(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: @select_or_icmp_inv( -; CHECK-NEXT: [[A:%.*]] = icmp ne i32 [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[B:%.*]] = icmp ne i32 [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]] -; CHECK-NEXT: [[D:%.*]] = select i1 [[C]], i32 [[Z]], i32 [[X]] -; CHECK-NEXT: ret i32 [[D]] +; CHECK-NEXT: ret i32 [[Z:%.*]] ; %A = icmp ne i32 %z, %x %B = icmp ne i32 %z, %y