Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -4478,6 +4478,29 @@ Pred == ICmpInst::ICMP_EQ); } +static Value *simplifySelectWithICmpEq(Value *CmpLHS, Value *CmpRHS, + Value *TrueVal, Value *FalseVal, + const SimplifyQuery &Q, + unsigned MaxRecurse) { + if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, + /* AllowRefinement */ false, + MaxRecurse) == TrueVal) + return FalseVal; + if (simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, + /* AllowRefinement */ true, + MaxRecurse) == FalseVal) + return FalseVal; + + Value *X; + Value *Y; + // select(X | Y == 0 ? X : 0) --> 0 (commuted 2 ways) + if (match(CmpLHS, m_c_Or(m_Specific(TrueVal), m_Value())) && + match(CmpRHS, m_Zero()) && match(FalseVal, m_ZeroInt())) + return FalseVal; + + return nullptr; +} + /// Try to simplify a select instruction when its condition operand is an /// integer comparison. static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, @@ -4566,20 +4589,12 @@ // 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. if (Pred == ICmpInst::ICMP_EQ) { - if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, - /* AllowRefinement */ false, - MaxRecurse) == TrueVal || - simplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q, - /* AllowRefinement */ false, - MaxRecurse) == TrueVal) - return FalseVal; - if (simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, - /* AllowRefinement */ true, - MaxRecurse) == FalseVal || - simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q, - /* AllowRefinement */ true, - MaxRecurse) == FalseVal) - return FalseVal; + if (Value *V = simplifySelectWithICmpEq(CmpLHS, CmpRHS, TrueVal, FalseVal, + Q, MaxRecurse)) + return V; + if (Value *V = simplifySelectWithICmpEq(CmpRHS, CmpLHS, TrueVal, FalseVal, + Q, MaxRecurse)) + return V; } if (Pred == ICmpInst::Predicate::ICMP_EQ) { Index: llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll =================================================================== --- llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll +++ llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll @@ -141,6 +141,7 @@ ret i32 %cond } +; TODO: https://alive2.llvm.org/ce/z/X6QjcB define i64 @select_clz_to_ctz_i64_wrong_xor(i64 %a) { ; CHECK-LABEL: @select_clz_to_ctz_i64_wrong_xor( ; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[A:%.*]] Index: llvm/test/Transforms/InstSimplify/select-cmp-or.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstSimplify/select-cmp-or.ll @@ -0,0 +1,60 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instsimplify,instcombine -S | FileCheck %s + +; TODO: https://alive2.llvm.org/ce/z/1ILbih +define i32 @select_icmp_and_eq(i32 %a, i32 %b) { +; CHECK-LABEL: @select_icmp_and_eq( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[AND]], -1 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[A]], i32 -1 +; CHECK-NEXT: ret i32 [[COND]] +; + %and = and i32 %a, %b + %tobool = icmp eq i32 %and, -1 + %cond = select i1 %tobool, i32 %a, i32 -1 + ret i32 %cond +} + +; https://alive2.llvm.org/ce/z/hSyCuR +define i32 @select_icmp_or_eq(i32 %a, i32 %b) { +; CHECK-LABEL: @select_icmp_or_eq( +; CHECK-NEXT: ret i32 0 +; + %or = or i32 %a, %b + %tobool = icmp eq i32 %or, 0 + %cond = select i1 %tobool, i32 %a, i32 0 + ret i32 %cond +} + +define i32 @select_icmp_or_eq_commuted(i32 %a0, i32 %b) { +; CHECK-LABEL: @select_icmp_or_eq_commuted( +; CHECK-NEXT: ret i32 0 +; + %a = mul i32 %a0, 43 ; thwart complexity-based canonicalization + %or = or i32 %a, %b + %tobool = icmp eq i32 %or, 0 + %cond = select i1 %tobool, i32 %b, i32 0 + ret i32 %cond +} + +; https://alive2.llvm.org/ce/z/S_pQek +define <2 x i16> @select_icmp_or_eq_vec(<2 x i16> %a, <2 x i16> %b) { +; CHECK-LABEL: @select_icmp_or_eq_vec( +; CHECK-NEXT: ret <2 x i16> zeroinitializer +; + %or = or <2 x i16> %a, %b + %tobool = icmp eq <2 x i16> %or, + %cond = select <2 x i1> %tobool, <2 x i16> %a, <2 x i16> zeroinitializer + ret <2 x i16> %cond +} + +; The ne will be normalized to eq above +define i32 @select_icmp_or_ne(i32 %a, i32 %b) { +; CHECK-LABEL: @select_icmp_or_ne( +; CHECK-NEXT: ret i32 0 +; + %or = or i32 %a, %b + %tobool = icmp ne i32 %or, 0 + %cond = select i1 %tobool, i32 0, i32 %a + ret i32 %cond +}