Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -54,6 +54,38 @@ return Builder.CreateSelect(Builder.CreateICmp(Pred, A, B), A, B); } +/// Fold +/// %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 +static Value *foldSelectInstBinaryOp(SelectInst &Sel) { + Value *A, *B; + Value *TrueVal = Sel.getTrueValue(); + Value *FalseVal = Sel.getFalseValue(); + if (match(Sel.getCondition(), m_c_Or(m_Value(A), m_Value(B)))) { + CmpInst::Predicate Pred1, Pred2; + Value *T1, *T2; + Value *F1, *F2; + if (match(A, m_c_ICmp(Pred1, m_Value(T1), m_Value(F1))) && + match(B, m_c_ICmp(Pred2, m_Value(T2), m_Value(F2)))) { + if (Pred1 == Pred2 && Pred1 == ICmpInst::ICMP_NE) { + if (T1 == FalseVal || T2 == FalseVal) + if (TrueVal == F1 && TrueVal == F2) + return TrueVal; + + if (F1 == FalseVal || F2 == FalseVal) + if (TrueVal == T1 && TrueVal == T2) + return TrueVal; + } + } + } + return nullptr; +} + /// This folds: /// select (icmp eq (and X, C1)), TC, FC /// iff C1 is a power 2 and the difference between TC and FC is a power-of-2. @@ -1681,6 +1713,10 @@ if (Instruction *Result = foldSelectInstWithICmp(SI, ICI)) return Result; + if (isa(CondVal)) + if (Value *V = foldSelectInstBinaryOp(SI)) + return replaceInstUsesWith(SI, V); + if (Instruction *Add = foldAddSubSelect(SI, Builder)) return Add; 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,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +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 +}