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 @@ -2990,6 +2990,11 @@ m_c_LogicalOr(m_Deferred(A), m_Deferred(B))))) return BinaryOperator::CreateXor(A, B); + // A & (~A | B) --> A & B + if (match(&SI, m_c_LogicalAnd(m_Value(A), m_c_LogicalOr(m_Not(m_Deferred(A)), + m_Value(B))))) + return BinaryOperator::CreateAnd(A, B); + // select (~a | c), a, b -> and a, (or c, freeze(b)) if (match(CondVal, m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))) && CondVal->hasOneUse()) { diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll --- a/llvm/test/Transforms/InstCombine/logical-select.ll +++ b/llvm/test/Transforms/InstCombine/logical-select.ll @@ -1121,3 +1121,15 @@ call void @use1(i1 %and1) ret i1 %r } + +; A & (~A | B) --> A & B +define <2 x i1> @and_commute(<2 x i1> %a, <2 x i1> %b) { +; CHECK-LABEL: @and_commute( +; CHECK-NEXT: [[AND:%.*]] = and <2 x i1> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: ret <2 x i1> [[AND]] +; + %not = xor <2 x i1> %a, + %or = select <2 x i1> %not, <2 x i1> , <2 x i1> %b + %and = select <2 x i1> %a, <2 x i1> %or, <2 x i1> zeroinitializer + ret <2 x i1> %and +}