Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -65,6 +65,33 @@ 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) { + Value *V1, *V2; + CmpInst::Predicate Pred1, Pred2; + if (match(Cond, m_c_Or(m_c_ICmp(Pred1, m_Deferred(TrueVal), m_Value(V1)), + m_c_ICmp(Pred2, m_Deferred(TrueVal), m_Value(V2))))) + if (FalseVal == V1 || FalseVal == V2) + if (Pred1 == Pred2 && Pred1 == ICmpInst::ICMP_NE) + return TrueVal; + if (match(Cond, m_c_And(m_c_ICmp(Pred1, m_Deferred(TrueVal), m_Value(V1)), + m_c_ICmp(Pred2, m_Deferred(TrueVal), m_Value(V2))))) + if (FalseVal == V1 || FalseVal == V2) + if (Pred1 == Pred2 && Pred1 == ICmpInst::ICMP_EQ) + return FalseVal; + return nullptr; +} + /// 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 +3779,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-or-cmp.ll =================================================================== --- test/Transforms/InstCombine/select-or-cmp.ll +++ test/Transforms/InstCombine/select-or-cmp.ll @@ -0,0 +1,92 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +define i32 @select_or_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp2( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %y + ret i32 %D +} + +define i32 @select_or_inv_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_inv_icmp( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %x, %z + %B = icmp ne i32 %y, %z + %C = or i1 %B , %A + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_or_icmp_inv(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_or_icmp_inv( +; CHECK-NEXT: ret i32 [[Z:%.*]] +; + %A = icmp ne i32 %z, %x + %B = icmp ne i32 %z, %y + %C = or i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp2(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp2( +; CHECK-NEXT: ret i32 [[Y:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %y + ret i32 %D +} + +define i32 @select_and_inv_icmp(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_inv_icmp( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %x, %z + %B = icmp eq i32 %y, %z + %C = and i1 %B , %A + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +} + +define i32 @select_and_icmp_inv(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @select_and_icmp_inv( +; CHECK-NEXT: ret i32 [[X:%.*]] +; + %A = icmp eq i32 %z, %x + %B = icmp eq i32 %z, %y + %C = and i1 %A, %B + %D = select i1 %C, i32 %z, i32 %x + ret i32 %D +}